Moved com.riiablo.excel2 to com.riiablo.excel

This commit is contained in:
Collin Smith
2020-12-12 19:45:23 -08:00
parent 23009f2521
commit d8570e136d
26 changed files with 827 additions and 2028 deletions

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
@ -12,33 +12,39 @@ import com.riiablo.logger.Logger;
public class BinGenerator {
private static final Logger log = LogManager.getLogger(BinGenerator.class);
String sourcePackage = "com.riiablo.excel2.txt";
String sourcePackage = "com.riiablo.excel.txt";
String excelPath = "DATA\\GLOBAL\\EXCEL2".toLowerCase(); // string will be defined elsewhere in caps
FileHandle binDir;
public void generateBins() {
log.info("Generating bins for {}...", sourcePackage);
BinGenerator configure(FileHandle binDir) {
this.binDir = binDir;
return this;
}
public <E extends Excel.Entry, S extends Serializer<E>, T extends Excel<E, S>>
void generateBin(T excel) {
final Class<? extends Excel> excelClass = excel.excelClass();
log.trace("excel: {}", excelClass.getCanonicalName());
public void generateBins() {
log.info("Generating bins for {}...", sourcePackage);
FileHandle excelDir = binDir.child(excelPath);
log.trace("excelDir: {}", excelDir);
excelDir.mkdirs();
generateBin(excelDir, null);
}
public <E extends Excel.Entry, S extends Serializer<E>, T extends Excel<E, S>>
void generateBin(FileHandle excelDir, T excel) {
final Class<? extends Excel> excelClass = excel.excelClass();
log.trace("excel: {}", excelClass.getCanonicalName());
FileHandle binFile = excelDir.child(excelClass.getSimpleName() + "." + "bin");
log.trace("binFile: {}", binFile);
ByteOutput out = ByteOutput.wrap(Unpooled.buffer());
S serializer = excel.newSerializer();
for (E entry : excel) {
serializer.writeBin(entry, out);
}
// S serializer = excel.newSerializer();
// for (E entry : excel) {
// serializer.writeBin(entry, out);
// }
log.trace("\n{}", ByteBufUtil.prettyHexDump(out.buffer()));
log.trace("dump of {}:\n{}", binFile, ByteBufUtil.prettyHexDump(out.buffer()));
}
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
public class ColumnFormat extends RuntimeException {
final String columnText;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,80 +1,100 @@
package com.riiablo.excel;
import android.support.annotation.CallSuper;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.tuple.Triple;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.badlogic.gdx.utils.ObjectMap;
import com.riiablo.io.ByteInput;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
import com.riiablo.logger.MDC;
import com.riiablo.util.ClassUtils;
public abstract class Excel<T extends Excel.Entry, U extends Serializer<T>> implements Iterable<T> {
/**
* Root class of an excel table.
*/
public abstract class Excel<
E extends Excel.Entry,
S extends Serializer<E>
>
implements Iterable<E>
{
private static final Logger log = LogManager.getLogger(Excel.class);
private static final boolean DEBUG = true;
private static final boolean DEBUG_COLS = DEBUG && !true;
private static final boolean DEBUG_COL_IDS = DEBUG && !true;
private static final boolean DEBUG_IGNORED = DEBUG && true;
private static final boolean DEBUG_ENTRIES = DEBUG && true;
private static final boolean DEBUG_INDEXES = DEBUG && true;
private static final boolean DEBUG_KEY = DEBUG && true;
private static final boolean DEBUG_BIN = DEBUG && true;
private static final boolean DEBUG_TIME = DEBUG && true;
/** Forces excels to either have a {@link PrimaryKey} set or be {@link Indexed} */
private static final boolean FORCE_PRIMARY_KEY = !true;
private static final boolean FORCE_TXT = !true;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Index {}
private static final ObjectIntMap EMPTY_OBJECT_INT_MAP = new ObjectIntMap();
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bin {}
@SuppressWarnings("unchecked") // doesn't store anything
static <T> ObjectIntMap<T> emptyMap() {
return (ObjectIntMap<T>) EMPTY_OBJECT_INT_MAP;
}
public static class Entry {
/**
* Root class of an excel entry.
*/
public static abstract class Entry {
/**
* Tags a specified field as a column within the excel table.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
/** Used to index format */
int startIndex() default 0;
/** Used to index format */
int endIndex() default 0;
/** Format of column name, if not set, then field name is used */
String format() default "";
/** Used to index format not non-numerical indexes */
String values()[] default {};
/** Sets index of column of value (used for cases like weapons.txt where one column has no name) */
int columnIndex() default -1;
/** Whether or not to read/write value in bin codec */
boolean bin() default true;
/**
* Start index of {@link #format()} (inclusive)
*/
int startIndex() default 0;
/**
* End index of {@link #format()} (exclusive)
*/
int endIndex() default 0;
/**
* String format of column name, {@code ""} to use field name
* <p>
* <p>Examples:
* <ul>
* <li>{@code "class"}
* <li>{@code "Transform Color"}
* <li>{@code "Level%s"}
* <li>{@code "Skill %d"}
*/
String format() default "";
/**
* Index values of format in the case of non-numerical indexes.
* <p>
* <p>Examples:
* <ul>
* <li>{@code {"", "(N)", "(H)"}}
* <li>{@code {"r", "g", "b"}}
* <li>{@code {"Min", "Max", "MagicMin", "MagicMax", "MagicLvl"}}
*/
String[] values() default {};
/**
* Manually sets the column index. This property overrides all other
* properties.
*/
int columnIndex() default -1;
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Key {}
}
private static final ObjectIntMap EMPTY_MAP = new ObjectIntMap();
@SuppressWarnings("unchecked")
public static <T> ObjectIntMap<T> emptyMap() {
return (ObjectIntMap<T>) EMPTY_MAP;
}
public static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
@ -84,83 +104,69 @@ public abstract class Excel<T extends Excel.Entry, U extends Serializer<T>> impl
public static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T load(T excel, FileHandle txt, FileHandle bin) throws IOException {
long start = System.currentTimeMillis();
final FileHandle handle;
final boolean loadBin;
if (!FORCE_TXT && bin != null && bin.exists()) {
handle = bin;
loadBin = true;
} else {
handle = txt;
loadBin = false;
}
log.debug("Parsing {}", handle);
try {
MDC.put("excelClass", excel.getClass().getCanonicalName());
try {
MDC.put("entryClass", excel.getEntryClass().getCanonicalName());
if (loadBin) {
loadBin(excel, bin);
} else {
loadTxt(excel, txt);
}
} finally {
MDC.remove("entryClass");
}
} finally {
MDC.remove("excelClass");
}
long end = System.currentTimeMillis();
if (DEBUG_TIME) log.debug("{} parsed in {} ms", handle, end - start);
return excel;
throw null;
}
private static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadTxt(T excel, FileHandle handle) throws IOException {
TxtParser parser = null;
InputStream in = handle.read();
try {
parser = TxtParser.parse(handle);
MDC.put("excel", handle.path());
TxtParser parser = TxtParser.parse(in);
return loadTxt(excel, parser);
} catch (IllegalAccessException t) {
log.error("Unable to load txt {}: {}",
} catch (Throwable t) {
log.fatal("Unable to load {} as {}: {}",
handle,
excel.getClass().getCanonicalName(),
ExceptionUtils.getRootCauseMessage(t),
t);
return ExceptionUtils.wrapAndThrow(t);
return ExceptionUtils.rethrow(t);
} finally {
IOUtils.closeQuietly(parser);
MDC.remove("excel");
IOUtils.closeQuietly(in);
}
}
private static <E extends Entry, T extends Excel<E, ?>>
T loadTxt(T excel, TxtParser parser) throws IOException, IllegalAccessException {
final Class<E> entryClass = excel.getEntryClass();
final boolean index = ClassUtils.hasAnnotation(entryClass, Index.class);
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadTxt(T excel, TxtParser parser)
throws IOException, ParseException, IllegalAccessException
{
final Class<E> entryClass = excel.entryClass();
final boolean indexed = ClassUtils.hasAnnotation(entryClass, Indexed.class);
final String[] TMP = new String[1];
Field primaryKey = null, firstKey = null;
ObjectMap<Field, int[]> columns = new ObjectMap<>();
String[] TMP = new String[1];
Array<Triple<Field, int[], String[]>> columns = new Array<>(true, parser.numColumns(), Triple.class);
for (Field field : entryClass.getFields()) {
Entry.Column column = field.getAnnotation(Entry.Column.class);
if (column == null) continue; // TODO: DEBUG MESSAGE WARNING
if (column == null) {
log.warn("{} is not tagged with {}", field, Entry.Column.class.getCanonicalName());
continue;
}
Entry.Key key = field.getAnnotation(Entry.Key.class);
PrimaryKey key = field.getAnnotation(PrimaryKey.class);
if (key != null) {
if (index) {
log.error("primary key set in class annotated with {}", Excel.Index.class);
if (!ArrayUtils.contains(PrimaryKey.SUPPORTED_TYPES, field.getType())) {
throw new ParseException(field, "%s must be one of %s",
field, Arrays.toString(PrimaryKey.SUPPORTED_TYPES));
}
if (indexed) {
// Indexed excels have their primary key assigned automatically based on row index
log.warn("{} has {} set to the primary key, but class is tagged with {}",
entryClass, field, Indexed.class.getCanonicalName());
} else if (primaryKey != null) {
// Allow declared field tagged as a primary key to override inherited ones
boolean primaryDeclared = ClassUtils.isDeclaredField(entryClass, primaryKey);
boolean fieldDeclared = ClassUtils.isDeclaredField(entryClass, field);
if (primaryDeclared != fieldDeclared) {
if (fieldDeclared) {
if (DEBUG_KEY) log.debug("primary key {} -> {}", primaryKey.getName(), field.getName());
log.debug("primary key {} changed to {}", primaryKey, field);
primaryKey = field;
}
} else {
log.error("more than one primary key for {}: {} and {}", entryClass, primaryKey.getName(), field.getName());
log.warn("multiple primary keys set within {}: {} and {}",
entryClass, primaryKey.getName(), field.getName());
}
} else {
primaryKey = field;
@ -168,255 +174,466 @@ public abstract class Excel<T extends Excel.Entry, U extends Serializer<T>> impl
}
if (firstKey == null) firstKey = field;
final String format = column.format();
final String values[] = column.values();
final int startIndex = column.startIndex();
final int endIndex = column.endIndex();
final int columnIndex = column.columnIndex();
if (columnIndex >= 0) {
columns.put(field, new int[] { columnIndex });
} else if (format.isEmpty()) {
final String fieldName = field.getName();
if (values.length > 0) {
String[] columnNames = new String[values.length];
for (int i = 0; i < values.length; i++) {
String name = values[i];
if (DEBUG_COLS) log.trace(name);
columnNames[i] = name;
}
columns.put(field, parser.getColumnId(columnNames));
} else if (startIndex == 0 && endIndex == 0) {
if (DEBUG_COLS) log.trace(fieldName);
TMP[0] = fieldName;
columns.put(field, parser.getColumnId(TMP));
} else {
String[] columnNames = new String[endIndex - startIndex];
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
String name = fieldName + i;
if (DEBUG_COLS) log.trace(name);
columnNames[j] = name;
}
columns.put(field, parser.getColumnId(columnNames));
}
} else {
if (startIndex == 0 && endIndex == 0) {
TMP[0] = format;
columns.put(field, parser.getColumnId(TMP));
} else {
String[] columnNames = new String[endIndex - startIndex];
if (values.length == 0) {
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
String name = String.format(format, i);
if (DEBUG_COLS) log.trace(name);
columnNames[j] = name;
}
} else {
for (int i = 0; i < values.length; i++) {
String name = String.format(format, values[i]);
if (DEBUG_COLS) log.trace(name);
columnNames[i] = name;
}
}
columns.put(field, parser.getColumnId(columnNames));
}
}
populateColumnIndexes(columns, parser, column, field, TMP);
}
if (primaryKey == null && !index) {
if (primaryKey == null && !indexed) {
if (FORCE_PRIMARY_KEY) {
throw new IllegalStateException(entryClass + " does not have a " + Entry.Key.class + " set!");
throw new ParseException(entryClass, "%s does not have a %s set!",
entryClass, PrimaryKey.class.getCanonicalName());
} else {
log.error("{} does not have a {} set! Using {}", entryClass, Entry.Key.class, firstKey.getName());
log.warn("{} does not have a {} set! Defaulting to first key: {}",
entryClass, PrimaryKey.class.getCanonicalName(), firstKey);
primaryKey = firstKey;
}
}
if (DEBUG_COL_IDS) {
for (ObjectMap.Entry<Field, int[]> entry : columns.entries()) {
log.debug("{}: {}", entry.key.getName(), entry.value);
// Locate the column index of the primary key
// TODO: this operation can be cleaned up, but this is only an identity test
int[] primaryKeyColumnIds = null;
final Triple<Field, int[], String[]>[] columnTriples = columns.items;
for (int i = 0, s = columnTriples.length; i < s; i++) {
if (columnTriples[i].getLeft() == primaryKey) {
primaryKeyColumnIds = columnTriples[i].getMiddle();
break;
}
}
final int primaryKeyCol = index ? -1 : columns.get(primaryKey)[0];
final Class primaryKeyType = index ? null : primaryKey.getType();
for (int i = excel.offset(); parser.nextLine() != null; i++) {
E entry = excel.newEntry();
String name = index ? null : parser.getString(primaryKeyCol);
try {
if (DEBUG_ENTRIES) MDC.put("index", i);
try {
if (DEBUG_ENTRIES) MDC.put("primaryKey", name);
for (ObjectMap.Entry<Field, int[]> row : columns.entries()) {
Field field = row.key;
int[] columnIds = row.value;
Class type = field.getType();
assert type.isArray() || columnIds.length == 1 : "field should only correspond to 1 column: " + field.getName() + ", " + columnIds.length + " columns (is it supposed to be an array?)";
if (type == String.class) {
String value = parser.getString(columnIds[0]);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == String[].class) {
String[] value = parser.getString(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == byte.class) {
byte value = parser.getByte(columnIds[0]);
field.setByte(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == byte[].class) {
byte[] value = parser.getByte(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == short.class) {
short value = parser.getShort(columnIds[0]);
field.setShort(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == short[].class) {
short[] value = parser.getShort(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == int.class) {
int value = parser.getInt(columnIds[0]);
field.setInt(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == int[].class) {
int[] value = parser.getInt(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == long.class) {
long value = parser.getLong(columnIds[0]);
field.setLong(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == long[].class) {
long[] value = parser.getLong(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == boolean.class) {
boolean value = parser.getBoolean(columnIds[0]);
field.setBoolean(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else if (type == boolean[].class) {
boolean[] value = parser.getBoolean(columnIds);
field.set(entry, value);
if (DEBUG_ENTRIES) log.trace("{}={}", field.getName(), value);
} else {
throw new UnsupportedOperationException("No support for " + type + " fields");
}
}
} finally {
if (DEBUG_ENTRIES) MDC.remove("primaryKey");
int nonzeroIndex = -1;
if (!indexed) {
for (int i = 0, s = primaryKeyColumnIds.length; i < s; i++) {
if (primaryKeyColumnIds[i] >= 0) {
nonzeroIndex = i;
break;
}
} finally {
if (DEBUG_ENTRIES) MDC.remove("index");
}
putIndex(primaryKey, primaryKeyType, i++, index, excel, entry);
if (nonzeroIndex == -1) {
throw new ParseException(primaryKey,
"primary key %s does not have any columns associated with it",
primaryKey);
}
}
final int primaryKeyColumnId = indexed ? -1 : primaryKeyColumnIds[nonzeroIndex];
final Class primaryKeyType = indexed ? null : primaryKey.getType();
for (int i = excel.offset(); parser.cacheLine() != -1; i++) {
E entry = excel.newEntry();
String name = indexed ? null : parser.parseString(primaryKeyColumnId, "");
try {
MDC.put("entry", indexed || StringUtils.isBlank(name) ? "" + i : name);
parseColumns(excel, entry, name, columns, parser);
} finally {
MDC.remove("entry");
}
putIndex(primaryKey, primaryKeyType, i++, indexed, excel, entry);
}
return excel;
}
private static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadBin(T excel, FileHandle handle) {
final Class<E> entryClass = excel.getEntryClass();
final boolean index = ClassUtils.hasAnnotation(entryClass, Index.class);
final S serializer = excel.newSerializer();
static void
catchParseException(
Throwable t,
Field field,
Class type,
String key,
String columnName,
CharSequence token
) {
ParseException parseException = new ParseException(t, field,
"error parsing field %s row: '%s' column: '%s': '%s' as %s",
field, key, columnName, token.toString(),
type.isArray() ? type.getComponentType().getCanonicalName() : type.getCanonicalName());
log.warn(parseException.getMessage(), parseException);
}
try {
Field primaryKey = ClassUtils.findField(entryClass, Entry.Key.class);
if (primaryKey == null && !index) {
if (FORCE_PRIMARY_KEY) {
throw new IllegalStateException(entryClass + " does not have a " + Entry.Key.class + " set!");
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
void parseColumns(
T excel,
E entry,
String key,
Array<Triple<Field, int[], String[]>> columns,
TxtParser parser
)
throws IllegalAccessException, ParseException
{
for (Triple<Field, int[], String[]> column : columns) {
final Field field = column.getLeft();
final int[] columnIds = column.getMiddle();
final int numColumns = columnIds.length;
final String[] columnNames = column.getRight();
final Class type = field.getType();
try {
if (type == String.class) {
try {
field.set(entry, parser.parseString(columnIds[0], ""));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == String[].class) {
final String[] value = new String[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseString(columnIds[i], "");
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == byte.class) {
try {
field.setByte(entry, parser.parseByte(columnIds[0], (byte) 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == byte[].class) {
final byte[] value = new byte[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseByte(columnIds[i], (byte) 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == short.class) {
try {
field.setShort(entry, parser.parseShort(columnIds[0], (short) 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == short[].class) {
final short[] value = new short[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseShort(columnIds[i], (short) 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == int.class) {
try {
field.setInt(entry, parser.parseInt(columnIds[0], 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == int[].class) {
final int[] value = new int[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseInt(columnIds[i], 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == long.class) {
try {
field.setLong(entry, parser.parseLong(columnIds[0], 0L));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == long[].class) {
final long[] value = new long[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseLong(columnIds[i], 0L);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == boolean.class) {
try {
field.setBoolean(entry, parser.parseBoolean(columnIds[0], false));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == boolean[].class) {
final boolean[] value = new boolean[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseBoolean(columnIds[i], false);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == float.class) {
try {
field.setFloat(entry, parser.parseFloat(columnIds[0], 0f));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == float[].class) {
final float[] value = new float[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseFloat(columnIds[i], 0f);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == double.class) {
try {
field.setDouble(entry, parser.parseDouble(columnIds[0], 0d));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == double[].class) {
final double[] value = new double[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseDouble(columnIds[i], 0d);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else {
throw new ParseException(field, "Cannot parse fields of type %s",
org.apache.commons.lang3.ClassUtils.getCanonicalName(type));
}
} catch (ColumnFormat t) {
ParseException parseException = new ParseException(field,
"error parsing field %s row: '%s' column: '%s': '%s' as %s",
field, key, columnNames[t.columnIndex()], t.columnText(),
type.isArray() ? type.getComponentType().getCanonicalName() : type.getCanonicalName());
parseException.initCause(t);
throw parseException;
}
}
}
/**
* Parses the specified field using it's column definition annotation to
* generate a list of column names and indexes associated with them. These
* indexes are then stored as a mapping from field to associated column
* indexes which can be used to retrieve data from the backing excel.
*/
static void populateColumnIndexes(
final Array<Triple<Field, int[], String[]>> columns,
final TxtParser parser,
final Entry.Column column,
final Field field,
final String[] TMP
) throws ParseException {
final String format = column.format();
final String[] values = column.values();
final int startIndex = column.startIndex();
final int endIndex = column.endIndex();
final int columnIndex = column.columnIndex();
if (columnIndex >= 0) {
final int[] columnIndexes = new int[] { columnIndex };
final String[] columnNames = new String[] { null };
columns.add(Triple.of(field, columnIndexes, columnNames));
log.trace("pushing column <{}>->{}", field, columnIndexes);
} else if (format.isEmpty()) {
final String fieldName = field.getName();
if (values.length > 0) {
// values[] used as literal column names
checkArrayColumns(field, values.length);
String[] columnNames = new String[values.length];
for (int i = 0; i < values.length; i++) {
columnNames[i] = values[i];
}
putColumns(columns, parser, field, columnNames);
} else if (startIndex == 0 && endIndex == 0) {
// field name used as literal column name
TMP[0] = fieldName;
putColumns(columns, parser, field, TMP);
} else {
// field name + indexes used as column names
checkArrayColumns(field, endIndex - startIndex);
String[] columnNames = new String[endIndex - startIndex];
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
columnNames[j] = fieldName + i;
}
putColumns(columns, parser, field, columnNames);
}
} else {
if (startIndex == 0 && endIndex == 0) {
// format used as literal column name
TMP[0] = format;
putColumns(columns, parser, field, TMP);
} else {
checkArrayColumns(field, endIndex - startIndex);
String[] columnNames = new String[endIndex - startIndex];
if (values.length == 0) {
// format used in conjunction with indexes as column names
// format must contain %d within it, replaced with indexes
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
columnNames[j] = String.format(format, i);
}
} else {
Field firstKey = entryClass.getFields()[0];
log.error("{} does not have a {} set! Using {}", entryClass, Entry.Key.class, firstKey.getName());
primaryKey = firstKey;
// format used in conjunction with values as column names
// format must contain as many values as indexes
for (int i = 0, s = values.length; i < s; i++) {
columnNames[i] = String.format(format, values[i]);
}
}
putColumns(columns, parser, field, columnNames);
}
}
if (log.debugEnabled()) {
StringBuilder builder = new StringBuilder(256);
builder.append('{');
for (Triple<Field, int[], String[]> pair : columns) {
builder
.append(pair.getLeft().getName())
.append('=')
.append(Arrays.toString(pair.getMiddle()))
.append(", ");
}
if (columns.size > 0) builder.setLength(builder.length() - 2);
builder.append('}');
log.debug("columns: {}", builder.toString());
}
}
static void checkArrayColumns(Field field, int length) throws ParseException {
if (!field.getType().isArray() && length > 1) {
throw new ParseException(field, ""
+ "field %s corresponds to multiple columns. "
+ "is it supposed to be an array type?", field);
}
}
static int putColumns(
Array<Triple<Field, int[], String[]>> columns,
TxtParser parser,
Field field,
String[] columnNames
) {
final int index = columns.size;
final int[] columnIndexes = parser.columnId(columnNames);
columns.add(Triple.of(field, columnIndexes, columnNames));
log.trace("pushing columns {}->{}", columnNames, columnIndexes);
if (log.warnEnabled()) {
for (int i = 0, s = columnIndexes.length; i < s; i++) {
if (columnIndexes[i] == -1) {
log.warn("Unable to parse column named '{}'", columnNames[i]);
}
}
Class primaryKeyType = index ? null : primaryKey.getType();
ByteInput in = ByteInput.wrap(handle.readBytes());
int size = in.readSafe32u();
log.debug("reading {} entries...", size);
for (int i = 0, j = excel.offset(); i < size; i++, j++) {
E entry = excel.newEntry();
serializer.readBin(entry, in);
putIndex(primaryKey, primaryKeyType, j, index, excel, entry);
}
return excel;
} catch (Throwable t) {
throw new GdxRuntimeException("Couldn't load excel: " + handle, t);
}
return index;
}
private static <E extends Entry, T extends Excel<E, ?>>
void putIndex(Field primaryKey, Class primaryKeyType, int i, boolean indexed, T excel, E entry) throws IllegalAccessException {
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadBin(T excel, FileHandle handle) {
throw null;
}
static <E extends Entry, T extends Excel<E, ?>>
void putIndex(
Field primaryKey,
Class primaryKeyType,
int i,
boolean indexed,
T excel,
E entry
) throws IllegalAccessException {
if (indexed) {
excel.put(i, entry);
excel._put(i, entry);
} else if (primaryKeyType == int.class) {
int id = primaryKey.getInt(entry);
excel.put(id, entry);
excel._put(id, entry);
} else if (primaryKeyType == String.class) {
String id = (String) primaryKey.get(entry);
excel.put(i, entry);
excel._put(i, entry);
if (excel.STRING_TO_ID == EMPTY_MAP) excel.STRING_TO_ID = new ObjectIntMap<>();
if (!excel.STRING_TO_ID.containsKey(id)) excel.STRING_TO_ID.put(id, i);
if (excel.stringToIndex == EMPTY_OBJECT_INT_MAP) excel.stringToIndex = new ObjectIntMap<>();
if (!excel.stringToIndex.containsKey(id)) excel.stringToIndex.put(id, i);
}
}
protected ObjectIntMap<String> STRING_TO_ID = emptyMap();
protected IntMap<T> entries = new IntMap<>();
protected Class<T> entryClass;
protected final Class<E> entryClass;
protected ObjectIntMap<String> stringToIndex;
protected IntMap<E> entries;
protected Array<Entry> ordered;
protected Excel(Class<T> entryClass) {
protected Excel(Class<E> entryClass) {
this(entryClass, 53);
}
protected Excel(Class<E> entryClass, int initialCapacity) {
this(entryClass, initialCapacity, 0.8f);
}
protected Excel(Class<E> entryClass, int initialCapacity, float loadFactor) {
this.entryClass = entryClass;
this.stringToIndex = emptyMap();
this.entries = new IntMap<>(initialCapacity, loadFactor);
this.ordered = new Array<>(true, (int) (initialCapacity * loadFactor), Entry.class);
}
@CallSuper
protected void put(int id, T value) {
public Class<? extends Excel> excelClass() {
return getClass();
}
public Class<E> entryClass() {
return entryClass;
}
final void _put(int id, E value) {
entries.put(id, value);
put(id, value);
}
protected void put(int id, E value) {}
protected int offset() {
return 0;
}
protected void init() {}
public T get(String id) {
public E get(String id) {
return get(index(id));
}
public T get(int id) {
T value = entries.get(id);
if (DEBUG_INDEXES) log.trace("{} = {}", id, value);
return value;
public E get(int id) {
return entries.get(id);
}
public int index(String id) {
return STRING_TO_ID.get(id, -1);
return stringToIndex.get(id, -1);
}
public int size() {
return entries.size;
}
public Class<T> getEntryClass() {
return entryClass;
}
public abstract E newEntry();
public abstract T newEntry();
public abstract U newSerializer();
public abstract S newSerializer();
@Override
public Iterator<T> iterator() {
public Iterator<E> iterator() {
return entries.values().iterator();
}
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.reflect.Field;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;

View File

@ -1,11 +1,11 @@
package com.riiablo.excel;
import java.io.IOException;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
public interface Serializer<T extends Excel.Entry> {
void readBin(T entry, ByteInput in) throws IOException;
void writeBin(T entry, ByteOutput out) throws IOException;
void readBin(T entry, ByteInput in);
void writeBin(T entry, ByteOutput out);
boolean equals(T e1, T e2);
void logErrors(T e1, T e2);
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import com.squareup.javapoet.JavaFile;
import java.io.File;
@ -13,8 +13,8 @@ import com.riiablo.util.ClassUtils;
public class SerializerGenerator {
private static final Logger log = LogManager.getLogger(SerializerGenerator.class);
String sourcePackage = "com.riiablo.excel2.txt";
String serializerPackage = "com.riiablo.excel2.serializer";
String sourcePackage = "com.riiablo.excel.txt";
String serializerPackage = "com.riiablo.excel.serializer";
FileHandle sourceDir;
FileHandle serializerDir;

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import com.squareup.javapoet.AnnotationSpec;
import com.squareup.javapoet.ClassName;
@ -22,7 +22,7 @@ import org.apache.commons.lang3.time.DateFormatUtils;
import com.badlogic.gdx.utils.Array;
import com.riiablo.excel2.Excel.Entry.Column;
import com.riiablo.excel.Excel.Entry.Column;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
import com.riiablo.logger.LogManager;
@ -43,7 +43,7 @@ public class SerializerSourceGenerator {
ClassName entryName;
public SerializerSourceGenerator() {
this("com.riiablo.excel2.txt", "com.riiablo.excel2.serializer");
this("com.riiablo.excel.txt", "com.riiablo.excel.serializer");
}
static final class ColumnInfo {

View File

@ -1,182 +1,278 @@
package com.riiablo.excel;
import java.io.BufferedReader;
import java.io.Closeable;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ByteArray;
import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
public class TxtParser implements Closeable {
public class TxtParser {
private static final Logger log = LogManager.getLogger(TxtParser.class);
private static final boolean DEBUG = true;
private static final boolean DEBUG_ROWS = DEBUG && true;
private static final int HT = '\t';
private static final int CR = '\r';
private static final int LF = '\n';
private static final boolean FORCE_BOOL = true; // logs error if boolean is not 0 or 1
private static final boolean FORCE_COLS = true; // ignores row if token count != columns count
private static final byte[] TO_UPPER;
static {
TO_UPPER = new byte[1 << Byte.SIZE];
for (int i = 0; i < TO_UPPER.length; i++) {
TO_UPPER[i] = (byte) i;
}
private static final String EXPANSION = "Expansion";
public static TxtParser parse(FileHandle handle) throws IOException {
return parse(handle.read());
for (int i = 'a'; i <= 'z'; i++) {
TO_UPPER[i] &= ~0x20;
}
}
private static final AsciiString EXPANSION = AsciiString.cached("EXPANSION");
public static TxtParser parse(InputStream in) throws IOException {
BufferedReader reader = null;
reader = IOUtils.buffer(new InputStreamReader(in, StandardCharsets.US_ASCII));
return new TxtParser(reader);
return parse(in, 8192);
}
final BufferedReader reader;
public static TxtParser parse(InputStream in, int bufferSize) throws IOException {
return new TxtParser(in, bufferSize);
}
final int numColumns;
final Array<String> columnNames;
final ObjectIntMap<String> columnIds;
final String columnNames[];
BufferedInputStream in;
AsciiString line;
int index;
final ByteArray cache;
final IntArray tokenOffsets;
int[] tokenOffsetsCache;
int numTokens;
String line;
String tokens[];
private TxtParser(BufferedReader reader) throws IOException {
this.reader = reader;
line = reader.readLine();
columnNames = StringUtils.splitPreserveAllTokens(line, '\t');
log.debug("columnNames: {}", (Object) columnNames);
TxtParser(InputStream in, int bufferSize) throws IOException {
this.in = IOUtils.buffer(in, bufferSize);
cache = new ByteArray(512);
columnNames = new Array<>();
columnIds = new ObjectIntMap<>();
for (int i = 0; i < columnNames.length; i++) {
String key = columnNames[i].toLowerCase();
if (!columnIds.containsKey(key)) columnIds.put(key, i);
numColumns = parseColumnNames();
log.info("numColumns: {}", numColumns);
log.debug("columnNames: {}", columnNames);
log.trace("columnIds: {}", columnIds);
tokenOffsets = new IntArray();
}
private static String toString(ByteArray array) {
if (array.size == 0) return "";
String stringValue = new String(array.items, 0, array.size, CharsetUtil.US_ASCII);
array.clear();
return stringValue;
}
private int parseColumnNames() throws IOException {
for (int i; (i = in.read()) != -1;) {
switch (i) {
case HT:
putColumnName(toString(cache));
break;
case CR:
in.skip(1);
case LF:
putColumnName(toString(cache));
return columnNames.size;
default:
cache.add(TO_UPPER[i]);
}
}
log.debug("columnIds: {}", columnIds);
throw new IOException("Unexpected end of file while parsing column names");
}
@Override
public void close() throws IOException {
reader.close();
private void putColumnName(String columnName) {
if (!columnIds.containsKey(columnName)) {
columnIds.put(columnName, columnNames.size);
}
columnNames.add(columnName);
}
public String[] getColumnNames() {
public int cacheLine() throws IOException {
cache.clear();
tokenOffsets.clear();
tokenOffsets.add(0);
index++;
lineBuilder:
for (;;) {
final int i = in.read();
switch (i) {
case -1:
return -1;
case HT:
tokenOffsets.add(cache.size);
break;
case CR:
in.skip(1);
case LF:
tokenOffsets.add(cache.size);
break lineBuilder;
default:
cache.add((byte) i);
}
}
numTokens = tokenOffsets.size - 1;
tokenOffsetsCache = tokenOffsets.items;
line = new AsciiString(cache.items, 0, cache.size, false);
log.debug("line: {}", line);
if (line.contentEqualsIgnoreCase(EXPANSION)) {
log.trace("skipping row {}: {} is an ignored symbol", index, EXPANSION);
return cacheLine();
}
if (numTokens != numColumns) {
log.warn("skipping row {}: contains {} tokens, expected {}; tokens: {}",
index, numTokens, numColumns, tokens());
return cacheLine();
}
if (log.traceEnabled()) {
final int[] tokenOffsets = this.tokenOffsets.items;
for (int i = 1, j = tokenOffsets[i - 1], s = this.tokenOffsets.size; i < s; i++) {
final int tokenOffset = tokenOffsets[i];
log.trace("{}={}", columnName(i - 1), line.subSequence(j, tokenOffset, false));
j = tokenOffset;
}
}
return tokenOffsets.size - 1;
}
public int numColumns() {
return numColumns;
}
public String[] columnNames() {
final String[] columnNames = new String[numColumns];
for (int i = 0; i < numColumns; i++) columnNames[i] = columnName(i);
return columnNames;
}
public int getNumColumns() {
return columnNames.length;
public String columnName(int i) {
return columnNames.get(i);
}
public String getColumnName(int i) {
return columnNames[i];
public String rowName() {
return parseString(0, "");
}
public String[] getTokens() {
return tokens;
public int columnId(String columnName) {
return columnIds.get(columnName.toUpperCase(), -1);
}
public int getNumTokens() {
return tokens.length;
}
public int getColumnId(String s) {
return columnIds.get(s.toLowerCase(), -1);
}
public int[] getColumnId(String[] s) {
int[] columnIds = new int[s.length];
for (int i = 0; i < s.length; i++) columnIds[i] = getColumnId(s[i]);
public int[] columnId(String[] columnNames) {
final int numColumns = columnNames.length;
final int[] columnIds = new int[numColumns];
for (int i = 0; i < numColumns; i++) columnIds[i] = columnId(columnNames[i]);
return columnIds;
}
public String nextLine() throws IOException {
index++;
line = reader.readLine();
if (line == null) {
return null;
} else if (line.equalsIgnoreCase(EXPANSION)) {
return nextLine();
public int numTokens() {
return numTokens;
}
public AsciiString[] tokens() {
final int numTokens = numTokens();
final AsciiString[] tokens = new AsciiString[numTokens];
for (int i = 0; i < numTokens; i++) tokens[i] = token(i);
return tokens;
}
public AsciiString token(int i) {
final int[] tokenOffsets = tokenOffsetsCache;
return line.subSequence(tokenOffsets[i], tokenOffsets[i + 1]);
}
public byte parseByte(int i, byte defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
final int intValue = line.parseInt(startOffset, endOffset);
final byte result = (byte) intValue;
if (result != intValue) {
throw new NumberFormatException(line.subSequence(startOffset, endOffset, false).toString());
}
return result;
}
public short parseShort(int i, short defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseShort(startOffset, endOffset);
}
public int parseInt(int i, int defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseInt(startOffset, endOffset);
}
public long parseLong(int i, long defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseLong(startOffset, endOffset);
}
public boolean parseBoolean(int i, boolean defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
final int intValue = line.parseInt(startOffset, endOffset);
if ((intValue & 1) != intValue) {
log.warn("boolean exceeds boolean radix at {}:{} (\"{}\", \"{}\"): {}",
index, i, rowName(), columnName(i), intValue);
}
tokens = StringUtils.splitPreserveAllTokens(line, '\t');
if (log.traceEnabled()) log.trace("{}: {}", (index - 1), Arrays.toString(tokens));
if (FORCE_COLS && tokens.length != columnNames.length) {
log.warn("skipping row {}: contains {} tokens, expected {}; tokens: {}",
index, tokens.length, columnNames.length, Arrays.toString(tokens));
return nextLine();
}
return line;
return intValue != 0;
}
public String getString(int i) {
return tokens[i];
public float parseFloat(int i, float defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseFloat(startOffset, endOffset);
}
public byte getByte(int i) {
return NumberUtils.toByte(tokens[i]);
public double parseDouble(int i, double defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseDouble(startOffset, endOffset);
}
public short getShort(int i) {
return NumberUtils.toShort(tokens[i]);
}
public int getInt(int i) {
return NumberUtils.toInt(tokens[i]);
}
public long getLong(int i) {
return NumberUtils.toLong(tokens[i]);
}
public boolean getBoolean(int i) {
int value = getInt(i);
if (FORCE_BOOL && (value & 1) != value) {
log.warn("boolean value != 0 or 1 at {}:{} (\"{}\", \"{}\"): {}",
index, i, getString(0), getColumnName(i), value);
}
return value != 0;
}
public String[] getString(int[] cols) {
String[] data = new String[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getString(cols[i]);
return data;
}
public byte[] getByte(int[] cols) {
byte[] data = new byte[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getByte(cols[i]);
return data;
}
public short[] getShort(int[] cols) {
short[] data = new short[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getShort(cols[i]);
return data;
}
public int[] getInt(int[] cols) {
int[] data = new int[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getInt(cols[i]);
return data;
}
public long[] getLong(int[] cols) {
long[] data = new long[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getLong(cols[i]);
return data;
}
public boolean[] getBoolean(int[] cols) {
boolean[] data = new boolean[cols.length];
for (int i = 0; i < cols.length; i++) data[i] = getBoolean(cols[i]);
return data;
public String parseString(int i, String defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.toString(tokenOffsets[i], tokenOffsets[i + 1]);
}
}

View File

@ -1,22 +0,0 @@
package com.riiablo.excel.gen;
import com.badlogic.gdx.files.FileHandle;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
public class BinGenerator {
private static final Logger log = LogManager.getLogger(BinGenerator.class);
public String serializerPackage;
public FileHandle serializerDir;
public String excelPath = "DATA\\GLOBAL\\EXCEL";
public FileHandle assetsDir;
public void generateBins() {
log.info("Generating bins for {}...", serializerPackage);
}
}

View File

@ -1,308 +0,0 @@
package com.riiablo.excel.gen;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.Arrays;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.output.ByteArrayOutputStream;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import com.badlogic.gdx.files.FileHandle;
import com.riiablo.excel.Excel;
import com.riiablo.excel.Excel.Entry;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
import com.riiablo.util.ClassUtils;
public class SerializerGenerator {
private static final Logger log = LogManager.getLogger(SerializerGenerator.class);
public String txtPackage;
public String binPackage;
public FileHandle txtDir;
public FileHandle binDir;
public int maxStringLen;
public String getSerializerPart() {
return "Bin";
}
public String formatSerializerName(String name) {
return StringUtils.appendIfMissingIgnoreCase(name, getSerializerPart());
}
private static Class findDeclaredClass(Class c, Class impl) throws ClassNotFoundException {
final Class[] classes = c.getDeclaredClasses();
for (Class declaredClass : classes) {
if (impl.isAssignableFrom(declaredClass)) {
return declaredClass;
}
}
throw new ClassNotFoundException(c + " does not implement " + impl);
}
public void generateSerializers() {
log.info("Generating serializers for {}...", txtDir);
FileHandle[] txtFiles = txtDir.list("java");
for (FileHandle txtFile : txtFiles) {
try {
generateSerializer(txtFile);
} catch (Throwable t) {
log.error("Error generating serializer for {}", txtFile, t);
}
}
}
public void generateSerializer(FileHandle txtFile)
throws ClassNotFoundException {
String txtName = txtFile.nameWithoutExtension();
log.trace("txtName: {}", txtName);
Class txtClass = Class.forName(txtPackage + "." + txtName);
// Prevent serializing literal Excel.class and non-subclasses of Excel.class
if (txtClass == Excel.class || !Excel.class.isAssignableFrom(txtClass)) {
return;
}
String binName = formatSerializerName(txtName);
log.trace("binName: {}", binName);
FileHandle binFile = binDir.child(binName + "." + "java");
log.info("{}->{}", txtFile, binFile);
// Find impls of Entry.class within txtClass
Class entryClass;
Class[] entryClasses = ClassUtils.findDeclaredClasses(txtClass, Entry.class);
switch (entryClasses.length) {
case 0:
log.error("{} does not contain an implementation of {}", txtClass, Entry.class);
return;
case 1:
entryClass = entryClasses[0];
log.trace("entryClass: {}", entryClass.getCanonicalName());
break;
default:
log.error("{} contains ambiguous implementations of {}: {}",
txtClass, Entry.class, Arrays.toString(entryClasses));
return;
}
if (!entryClass.getSimpleName().equals(Entry.class.getSimpleName())) {
log.warn("entry class {} not named {}",
entryClass.getCanonicalName(),
txtClass.getCanonicalName() + "$" + Entry.class.getSimpleName());
// return; // Allow it for now
}
Context context = new Context();
context.txtClass = txtClass;
context.entryClass = entryClass;
context.binName = binName;
context.binPackage = binPackage;
PrintStream out = System.out;
try {
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
out = new PrintStream(outStream, false, "UTF-8");
writeSerializer(out, context);
byte[] bytes = IOUtils.toByteArray(outStream.toInputStream());
binFile.writeBytes(bytes, false);
} catch (Throwable t) {
ExceptionUtils.rethrow(t);
return;
}
}
static class Context {
public Class txtClass;
public Class entryClass;
public String binName;
public String binPackage;
public int indent = 2;
public int currentIndent = 0;
String indentSpaces = "";
public String push() {
return indentSpaces = StringUtils.repeat(' ', currentIndent += indent);
}
public String pop() {
assert currentIndent >= 0 : "currentIndent(" + currentIndent + ") < " + 0;
return indentSpaces = StringUtils.repeat(' ', currentIndent -= indent);
}
public String peek() {
return indentSpaces;
}
}
void writeSerializer(PrintStream out, Context context) {
out.println("package " + context.binPackage + ";");
out.println();
out.println("import " + StringUtils.class.getCanonicalName() + ";");
out.println();
out.println("public class " + context.binName + " {");
context.push();
print_readBin(out, context);
out.println();
print_writeBin(out, context);
out.println();
print_equals(out, context);
out.println();
print_validate(out, context);
context.pop();
out.println("}");
out.println();
}
void print_readBin(PrintStream out, Context context) {
out.print(context.peek());
out.printf("public static void readBin(%s entry, %s in) throws java.io.IOException {%n",
context.entryClass.getCanonicalName(), ByteInput.class.getName());
String indent = context.push();
for (Field field : context.entryClass.getFields()) {
log.trace("Creating readBin for {}", field);
// if (field.getAnnotation(Excel.Entry.Key.class) != null) continue;
Excel.Entry.Column column = field.getAnnotation(Excel.Entry.Column.class);
if (!column.bin()) continue;
Class type = field.getType();
if (type.isArray()) {
type = type.getComponentType();
out.print(indent);
out.printf("entry.%s = new %s[%d];%n", field.getName(), type.getSimpleName(), column.endIndex() - column.startIndex());
out.print(indent);
if (type == String.class) {
out.printf("for (int x = %d; x < %d; x++) entry.%s[x] = in.read%s(%d, %b);%n", 0, column.endIndex() - column.startIndex(), field.getName(), getMethod(field), maxStringLen, true);
} else {
out.printf("for (int x = %d; x < %d; x++) entry.%s[x] = in.read%s();%n", 0, column.endIndex() - column.startIndex(), field.getName(), getMethod(field));
}
} else {
out.print(indent);
if (type == String.class) {
out.printf("entry.%s = in.read%s(%d, %b);%n", field.getName(), getMethod(field), maxStringLen, true);
} else {
out.printf("entry.%s = in.read%s();%n", field.getName(), getMethod(field));
}
}
}
out.print(context.pop());
out.println("}");
}
void print_writeBin(PrintStream out, Context context) {
out.print(context.peek());
out.printf("public static void writeBin(%s entry, %s out) throws java.io.IOException {%n",
context.entryClass.getCanonicalName(), ByteOutput.class.getName());
String indent = context.push();
for (Field field : context.entryClass.getFields()) {
Excel.Entry.Column column = field.getAnnotation(Excel.Entry.Column.class);
if (!column.bin()) continue;
Class type = field.getType();
out.print(indent);
if (type.isArray()) {
type = type.getComponentType();
if (type == String.class) {
out.printf("for (%s x : entry.%s) out.write%s(StringUtils.defaultString(x));%n", type.getSimpleName(), field.getName(), getMethod(field));
} else {
out.printf("for (%s x : entry.%s) out.write%s(x);%n", type.getSimpleName(), field.getName(), getMethod(field));
}
} else {
if (type == String.class) {
out.printf("out.write%s(StringUtils.defaultString(entry.%s));%n", getMethod(field), field.getName());
} else {
out.printf("out.write%s(entry.%s);%n", getMethod(field), field.getName());
}
}
}
out.print(context.pop());
out.println("}");
}
void print_equals(PrintStream out, Context context) {
out.print(context.peek());
out.printf("public static boolean equals(%s e1, %s e2) {%n",
context.entryClass.getCanonicalName(), context.entryClass.getCanonicalName());
String indent = context.push();
for (Field field : context.entryClass.getFields()) {
Excel.Entry.Column column = field.getAnnotation(Excel.Entry.Column.class);
if (!column.bin()) continue;
Class type = field.getType();
out.print(indent);
if (type.isArray()) {
out.printf("if (!java.util.Arrays.equals(e1.%s, e2.%s)) return false;%n", field.getName(), field.getName());
} else if (type.isPrimitive()) {
out.printf("if (e1.%s != e2.%s) return false;%n", field.getName(), field.getName());
} else {
out.printf("if (!java.util.Objects.equals(e1.%s, e2.%s)) return false;%n", field.getName(), field.getName());
}
}
out.print(indent);
out.println("return true;");
out.print(context.pop());
out.println("}");
}
void print_validate(PrintStream out, Context context) {
out.print(context.peek());
out.printf("public static void validate(%s log, %s e1, %s e2) {%n",
Logger.class.getCanonicalName(), context.entryClass.getCanonicalName(), context.entryClass.getCanonicalName());
String indent = context.push();
for (Field field : context.entryClass.getFields()) {
Excel.Entry.Column column = field.getAnnotation(Excel.Entry.Column.class);
if (!column.bin()) continue;
Class type = field.getType();
out.print(indent);
if (type.isArray()) {
out.printf("if (!java.util.Arrays.equals(e1.%s, e2.%s)) log.warn(\"%s does not match: e1=\" + e1.%s + \" e2=\" + e2.%s);%n", field.getName(), field.getName(), field.getName(), field.getName(), field.getName());
} else if (type.isPrimitive()) {
out.printf("if (e1.%s != e2.%s) log.warn(\"%s does not match: e1=\" + e1.%s + \" e2=\" + e2.%s);%n", field.getName(), field.getName(), field.getName(), field.getName(), field.getName());
} else {
out.printf("if (!java.util.Objects.equals(e1.%s, e2.%s)) log.warn(\"%s does not match: e1=\" + e1.%s + \" e2=\" + e2.%s);%n", field.getName(), field.getName(), field.getName(), field.getName(), field.getName());
}
}
out.print(context.pop());
out.println("}");
}
private static String getMethod(Field field) {
Class type = field.getType();
if (type.isArray()) {
type = type.getComponentType();
}
if (type == String.class) {
return "String";
} else if (type == byte.class) {
return "8";
} else if (type == short.class) {
return "16";
} else if (type == int.class) {
return "32";
} else if (type == long.class) {
return "64";
} else if (type == boolean.class) {
return "Boolean";
} else {
throw new UnsupportedOperationException(
"No support for " + type.getCanonicalName() + " fields");
}
}
}

View File

@ -1,12 +1,18 @@
package com.riiablo.excel.txt;
import com.riiablo.excel.Entry;
import com.riiablo.excel.Excel;
import com.riiablo.excel.PrimaryKey;
import com.riiablo.excel.SerializedWith;
import com.riiablo.excel.serializer.MonStatsSerializer;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
public class MonStats extends Excel<MonStats.Entry, MonStats.Serializer> {
@Entry(MonStats.Entry.class)
@SerializedWith(MonStatsSerializer.class)
public class MonStats extends Excel<MonStats.Entry, MonStatsSerializer> {
public MonStats() {
super(Entry.class);
super(Entry.class, 1543); // 736 entries
}
@Override
@ -15,8 +21,8 @@ public class MonStats extends Excel<MonStats.Entry, MonStats.Serializer> {
}
@Override
public Serializer newSerializer() {
return new Serializer();
public MonStatsSerializer newSerializer() {
return new MonStatsSerializer();
}
public static class Entry extends Excel.Entry {
@ -25,7 +31,7 @@ public class MonStats extends Excel<MonStats.Entry, MonStats.Serializer> {
return NameStr;
}
@Key
@PrimaryKey
@Column public String Id;
@Column public int hcIdx;
@Column public String BaseId;
@ -236,5 +242,7 @@ public class MonStats extends Excel<MonStats.Entry, MonStats.Serializer> {
public static class Serializer implements com.riiablo.excel.Serializer<Entry> {
@Override public void readBin(Entry entry, ByteInput in) {}
@Override public void writeBin(Entry entry, ByteOutput out) {}
@Override public boolean equals(Entry e1, Entry e2) { throw new UnsupportedOperationException(); }
@Override public void logErrors(Entry e1, Entry e2) {}
}
}

View File

@ -1,639 +0,0 @@
package com.riiablo.excel2;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Iterator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.commons.lang3.tuple.Triple;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
import com.riiablo.logger.MDC;
import com.riiablo.util.ClassUtils;
/**
* Root class of an excel table.
*/
public abstract class Excel<
E extends Excel.Entry,
S extends Serializer<E>
>
implements Iterable<E>
{
private static final Logger log = LogManager.getLogger(Excel.class);
/** Forces excels to either have a {@link PrimaryKey} set or be {@link Indexed} */
private static final boolean FORCE_PRIMARY_KEY = !true;
private static final ObjectIntMap EMPTY_OBJECT_INT_MAP = new ObjectIntMap();
@SuppressWarnings("unchecked") // doesn't store anything
static <T> ObjectIntMap<T> emptyMap() {
return (ObjectIntMap<T>) EMPTY_OBJECT_INT_MAP;
}
/**
* Root class of an excel entry.
*/
public static abstract class Entry {
/**
* Tags a specified field as a column within the excel table.
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
/**
* Start index of {@link #format()} (inclusive)
*/
int startIndex() default 0;
/**
* End index of {@link #format()} (exclusive)
*/
int endIndex() default 0;
/**
* String format of column name, {@code ""} to use field name
* <p>
* <p>Examples:
* <ul>
* <li>{@code "class"}
* <li>{@code "Transform Color"}
* <li>{@code "Level%s"}
* <li>{@code "Skill %d"}
*/
String format() default "";
/**
* Index values of format in the case of non-numerical indexes.
* <p>
* <p>Examples:
* <ul>
* <li>{@code {"", "(N)", "(H)"}}
* <li>{@code {"r", "g", "b"}}
* <li>{@code {"Min", "Max", "MagicMin", "MagicMax", "MagicLvl"}}
*/
String[] values() default {};
/**
* Manually sets the column index. This property overrides all other
* properties.
*/
int columnIndex() default -1;
}
}
public static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T load(T excel, FileHandle txt) throws IOException {
return load(excel, txt, null);
}
public static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T load(T excel, FileHandle txt, FileHandle bin) throws IOException {
throw null;
}
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadTxt(T excel, FileHandle handle) throws IOException {
InputStream in = handle.read();
try {
MDC.put("excel", handle.path());
TxtParser parser = TxtParser.parse(in);
return loadTxt(excel, parser);
} catch (Throwable t) {
log.fatal("Unable to load {} as {}: {}",
handle,
excel.getClass().getCanonicalName(),
ExceptionUtils.getRootCauseMessage(t),
t);
return ExceptionUtils.rethrow(t);
} finally {
MDC.remove("excel");
IOUtils.closeQuietly(in);
}
}
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadTxt(T excel, TxtParser parser)
throws IOException, ParseException, IllegalAccessException
{
final Class<E> entryClass = excel.entryClass();
final boolean indexed = ClassUtils.hasAnnotation(entryClass, Indexed.class);
final String[] TMP = new String[1];
Field primaryKey = null, firstKey = null;
Array<Triple<Field, int[], String[]>> columns = new Array<>(true, parser.numColumns(), Triple.class);
for (Field field : entryClass.getFields()) {
Entry.Column column = field.getAnnotation(Entry.Column.class);
if (column == null) {
log.warn("{} is not tagged with {}", field, Entry.Column.class.getCanonicalName());
continue;
}
PrimaryKey key = field.getAnnotation(PrimaryKey.class);
if (key != null) {
if (!ArrayUtils.contains(PrimaryKey.SUPPORTED_TYPES, field.getType())) {
throw new ParseException(field, "%s must be one of %s",
field, Arrays.toString(PrimaryKey.SUPPORTED_TYPES));
}
if (indexed) {
// Indexed excels have their primary key assigned automatically based on row index
log.warn("{} has {} set to the primary key, but class is tagged with {}",
entryClass, field, Indexed.class.getCanonicalName());
} else if (primaryKey != null) {
// Allow declared field tagged as a primary key to override inherited ones
boolean primaryDeclared = ClassUtils.isDeclaredField(entryClass, primaryKey);
boolean fieldDeclared = ClassUtils.isDeclaredField(entryClass, field);
if (primaryDeclared != fieldDeclared) {
if (fieldDeclared) {
log.debug("primary key {} changed to {}", primaryKey, field);
primaryKey = field;
}
} else {
log.warn("multiple primary keys set within {}: {} and {}",
entryClass, primaryKey.getName(), field.getName());
}
} else {
primaryKey = field;
}
}
if (firstKey == null) firstKey = field;
populateColumnIndexes(columns, parser, column, field, TMP);
}
if (primaryKey == null && !indexed) {
if (FORCE_PRIMARY_KEY) {
throw new ParseException(entryClass, "%s does not have a %s set!",
entryClass, PrimaryKey.class.getCanonicalName());
} else {
log.warn("{} does not have a {} set! Defaulting to first key: {}",
entryClass, PrimaryKey.class.getCanonicalName(), firstKey);
primaryKey = firstKey;
}
}
// Locate the column index of the primary key
// TODO: this operation can be cleaned up, but this is only an identity test
int[] primaryKeyColumnIds = null;
final Triple<Field, int[], String[]>[] columnTriples = columns.items;
for (int i = 0, s = columnTriples.length; i < s; i++) {
if (columnTriples[i].getLeft() == primaryKey) {
primaryKeyColumnIds = columnTriples[i].getMiddle();
break;
}
}
int nonzeroIndex = -1;
if (!indexed) {
for (int i = 0, s = primaryKeyColumnIds.length; i < s; i++) {
if (primaryKeyColumnIds[i] >= 0) {
nonzeroIndex = i;
break;
}
}
if (nonzeroIndex == -1) {
throw new ParseException(primaryKey,
"primary key %s does not have any columns associated with it",
primaryKey);
}
}
final int primaryKeyColumnId = indexed ? -1 : primaryKeyColumnIds[nonzeroIndex];
final Class primaryKeyType = indexed ? null : primaryKey.getType();
for (int i = excel.offset(); parser.cacheLine() != -1; i++) {
E entry = excel.newEntry();
String name = indexed ? null : parser.parseString(primaryKeyColumnId, "");
try {
MDC.put("entry", indexed || StringUtils.isBlank(name) ? "" + i : name);
parseColumns(excel, entry, name, columns, parser);
} finally {
MDC.remove("entry");
}
putIndex(primaryKey, primaryKeyType, i++, indexed, excel, entry);
}
return excel;
}
static void
catchParseException(
Throwable t,
Field field,
Class type,
String key,
String columnName,
CharSequence token
) {
ParseException parseException = new ParseException(t, field,
"error parsing field %s row: '%s' column: '%s': '%s' as %s",
field, key, columnName, token.toString(),
type.isArray() ? type.getComponentType().getCanonicalName() : type.getCanonicalName());
log.warn(parseException.getMessage(), parseException);
}
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
void parseColumns(
T excel,
E entry,
String key,
Array<Triple<Field, int[], String[]>> columns,
TxtParser parser
)
throws IllegalAccessException, ParseException
{
for (Triple<Field, int[], String[]> column : columns) {
final Field field = column.getLeft();
final int[] columnIds = column.getMiddle();
final int numColumns = columnIds.length;
final String[] columnNames = column.getRight();
final Class type = field.getType();
try {
if (type == String.class) {
try {
field.set(entry, parser.parseString(columnIds[0], ""));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == String[].class) {
final String[] value = new String[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseString(columnIds[i], "");
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == byte.class) {
try {
field.setByte(entry, parser.parseByte(columnIds[0], (byte) 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == byte[].class) {
final byte[] value = new byte[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseByte(columnIds[i], (byte) 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == short.class) {
try {
field.setShort(entry, parser.parseShort(columnIds[0], (short) 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == short[].class) {
final short[] value = new short[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseShort(columnIds[i], (short) 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == int.class) {
try {
field.setInt(entry, parser.parseInt(columnIds[0], 0));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == int[].class) {
final int[] value = new int[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseInt(columnIds[i], 0);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == long.class) {
try {
field.setLong(entry, parser.parseLong(columnIds[0], 0L));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == long[].class) {
final long[] value = new long[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseLong(columnIds[i], 0L);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == boolean.class) {
try {
field.setBoolean(entry, parser.parseBoolean(columnIds[0], false));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == boolean[].class) {
final boolean[] value = new boolean[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseBoolean(columnIds[i], false);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == float.class) {
try {
field.setFloat(entry, parser.parseFloat(columnIds[0], 0f));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == float[].class) {
final float[] value = new float[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseFloat(columnIds[i], 0f);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else if (type == double.class) {
try {
field.setDouble(entry, parser.parseDouble(columnIds[0], 0d));
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[0], parser.token(columnIds[0]));
}
} else if (type == double[].class) {
final double[] value = new double[numColumns];
for (int i = 0; i < numColumns; i++) {
try {
value[i] = parser.parseDouble(columnIds[i], 0d);
} catch (Throwable t) {
catchParseException(t, field, type, key, columnNames[i], parser.token(columnIds[i]));
}
}
field.set(entry, value);
}
else {
throw new ParseException(field, "Cannot parse fields of type %s",
org.apache.commons.lang3.ClassUtils.getCanonicalName(type));
}
} catch (ColumnFormat t) {
ParseException parseException = new ParseException(field,
"error parsing field %s row: '%s' column: '%s': '%s' as %s",
field, key, columnNames[t.columnIndex()], t.columnText(),
type.isArray() ? type.getComponentType().getCanonicalName() : type.getCanonicalName());
parseException.initCause(t);
throw parseException;
}
}
}
/**
* Parses the specified field using it's column definition annotation to
* generate a list of column names and indexes associated with them. These
* indexes are then stored as a mapping from field to associated column
* indexes which can be used to retrieve data from the backing excel.
*/
static void populateColumnIndexes(
final Array<Triple<Field, int[], String[]>> columns,
final TxtParser parser,
final Entry.Column column,
final Field field,
final String[] TMP
) throws ParseException {
final String format = column.format();
final String[] values = column.values();
final int startIndex = column.startIndex();
final int endIndex = column.endIndex();
final int columnIndex = column.columnIndex();
if (columnIndex >= 0) {
final int[] columnIndexes = new int[] { columnIndex };
final String[] columnNames = new String[] { null };
columns.add(Triple.of(field, columnIndexes, columnNames));
log.trace("pushing column <{}>->{}", field, columnIndexes);
} else if (format.isEmpty()) {
final String fieldName = field.getName();
if (values.length > 0) {
// values[] used as literal column names
checkArrayColumns(field, values.length);
String[] columnNames = new String[values.length];
for (int i = 0; i < values.length; i++) {
columnNames[i] = values[i];
}
putColumns(columns, parser, field, columnNames);
} else if (startIndex == 0 && endIndex == 0) {
// field name used as literal column name
TMP[0] = fieldName;
putColumns(columns, parser, field, TMP);
} else {
// field name + indexes used as column names
checkArrayColumns(field, endIndex - startIndex);
String[] columnNames = new String[endIndex - startIndex];
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
columnNames[j] = fieldName + i;
}
putColumns(columns, parser, field, columnNames);
}
} else {
if (startIndex == 0 && endIndex == 0) {
// format used as literal column name
TMP[0] = format;
putColumns(columns, parser, field, TMP);
} else {
checkArrayColumns(field, endIndex - startIndex);
String[] columnNames = new String[endIndex - startIndex];
if (values.length == 0) {
// format used in conjunction with indexes as column names
// format must contain %d within it, replaced with indexes
for (int i = startIndex, j = 0; i < endIndex; i++, j++) {
columnNames[j] = String.format(format, i);
}
} else {
// format used in conjunction with values as column names
// format must contain as many values as indexes
for (int i = 0, s = values.length; i < s; i++) {
columnNames[i] = String.format(format, values[i]);
}
}
putColumns(columns, parser, field, columnNames);
}
}
if (log.debugEnabled()) {
StringBuilder builder = new StringBuilder(256);
builder.append('{');
for (Triple<Field, int[], String[]> pair : columns) {
builder
.append(pair.getLeft().getName())
.append('=')
.append(Arrays.toString(pair.getMiddle()))
.append(", ");
}
if (columns.size > 0) builder.setLength(builder.length() - 2);
builder.append('}');
log.debug("columns: {}", builder.toString());
}
}
static void checkArrayColumns(Field field, int length) throws ParseException {
if (!field.getType().isArray() && length > 1) {
throw new ParseException(field, ""
+ "field %s corresponds to multiple columns. "
+ "is it supposed to be an array type?", field);
}
}
static int putColumns(
Array<Triple<Field, int[], String[]>> columns,
TxtParser parser,
Field field,
String[] columnNames
) {
final int index = columns.size;
final int[] columnIndexes = parser.columnId(columnNames);
columns.add(Triple.of(field, columnIndexes, columnNames));
log.trace("pushing columns {}->{}", columnNames, columnIndexes);
if (log.warnEnabled()) {
for (int i = 0, s = columnIndexes.length; i < s; i++) {
if (columnIndexes[i] == -1) {
log.warn("Unable to parse column named '{}'", columnNames[i]);
}
}
}
return index;
}
static <E extends Entry, S extends Serializer<E>, T extends Excel<E, S>>
T loadBin(T excel, FileHandle handle) {
throw null;
}
static <E extends Entry, T extends Excel<E, ?>>
void putIndex(
Field primaryKey,
Class primaryKeyType,
int i,
boolean indexed,
T excel,
E entry
) throws IllegalAccessException {
if (indexed) {
excel._put(i, entry);
} else if (primaryKeyType == int.class) {
int id = primaryKey.getInt(entry);
excel._put(id, entry);
} else if (primaryKeyType == String.class) {
String id = (String) primaryKey.get(entry);
excel._put(i, entry);
if (excel.stringToIndex == EMPTY_OBJECT_INT_MAP) excel.stringToIndex = new ObjectIntMap<>();
if (!excel.stringToIndex.containsKey(id)) excel.stringToIndex.put(id, i);
}
}
protected final Class<E> entryClass;
protected ObjectIntMap<String> stringToIndex;
protected IntMap<E> entries;
protected Array<Entry> ordered;
protected Excel(Class<E> entryClass) {
this(entryClass, 53);
}
protected Excel(Class<E> entryClass, int initialCapacity) {
this(entryClass, initialCapacity, 0.8f);
}
protected Excel(Class<E> entryClass, int initialCapacity, float loadFactor) {
this.entryClass = entryClass;
this.stringToIndex = emptyMap();
this.entries = new IntMap<>(initialCapacity, loadFactor);
this.ordered = new Array<>(true, (int) (initialCapacity * loadFactor), Entry.class);
}
public Class<? extends Excel> excelClass() {
return getClass();
}
public Class<E> entryClass() {
return entryClass;
}
final void _put(int id, E value) {
entries.put(id, value);
put(id, value);
}
protected void put(int id, E value) {}
protected int offset() {
return 0;
}
protected void init() {}
public E get(String id) {
return get(index(id));
}
public E get(int id) {
return entries.get(id);
}
public int index(String id) {
return stringToIndex.get(id, -1);
}
public int size() {
return entries.size;
}
public abstract E newEntry();
public abstract S newSerializer();
@Override
public Iterator<E> iterator() {
return entries.values().iterator();
}
}

View File

@ -1,11 +0,0 @@
package com.riiablo.excel2;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
public interface Serializer<T extends Excel.Entry> {
void readBin(T entry, ByteInput in);
void writeBin(T entry, ByteOutput out);
boolean equals(T e1, T e2);
void logErrors(T e1, T e2);
}

View File

@ -1,278 +0,0 @@
package com.riiablo.excel2;
import io.netty.util.AsciiString;
import io.netty.util.CharsetUtil;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.ByteArray;
import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.ObjectIntMap;
import com.riiablo.logger.LogManager;
import com.riiablo.logger.Logger;
public class TxtParser {
private static final Logger log = LogManager.getLogger(TxtParser.class);
private static final int HT = '\t';
private static final int CR = '\r';
private static final int LF = '\n';
private static final byte[] TO_UPPER;
static {
TO_UPPER = new byte[1 << Byte.SIZE];
for (int i = 0; i < TO_UPPER.length; i++) {
TO_UPPER[i] = (byte) i;
}
for (int i = 'a'; i <= 'z'; i++) {
TO_UPPER[i] &= ~0x20;
}
}
private static final AsciiString EXPANSION = AsciiString.cached("EXPANSION");
public static TxtParser parse(InputStream in) throws IOException {
return parse(in, 8192);
}
public static TxtParser parse(InputStream in, int bufferSize) throws IOException {
return new TxtParser(in, bufferSize);
}
final int numColumns;
final Array<String> columnNames;
final ObjectIntMap<String> columnIds;
BufferedInputStream in;
AsciiString line;
int index;
final ByteArray cache;
final IntArray tokenOffsets;
int[] tokenOffsetsCache;
int numTokens;
TxtParser(InputStream in, int bufferSize) throws IOException {
this.in = IOUtils.buffer(in, bufferSize);
cache = new ByteArray(512);
columnNames = new Array<>();
columnIds = new ObjectIntMap<>();
numColumns = parseColumnNames();
log.info("numColumns: {}", numColumns);
log.debug("columnNames: {}", columnNames);
log.trace("columnIds: {}", columnIds);
tokenOffsets = new IntArray();
}
private static String toString(ByteArray array) {
if (array.size == 0) return "";
String stringValue = new String(array.items, 0, array.size, CharsetUtil.US_ASCII);
array.clear();
return stringValue;
}
private int parseColumnNames() throws IOException {
for (int i; (i = in.read()) != -1;) {
switch (i) {
case HT:
putColumnName(toString(cache));
break;
case CR:
in.skip(1);
case LF:
putColumnName(toString(cache));
return columnNames.size;
default:
cache.add(TO_UPPER[i]);
}
}
throw new IOException("Unexpected end of file while parsing column names");
}
private void putColumnName(String columnName) {
if (!columnIds.containsKey(columnName)) {
columnIds.put(columnName, columnNames.size);
}
columnNames.add(columnName);
}
public int cacheLine() throws IOException {
cache.clear();
tokenOffsets.clear();
tokenOffsets.add(0);
index++;
lineBuilder:
for (;;) {
final int i = in.read();
switch (i) {
case -1:
return -1;
case HT:
tokenOffsets.add(cache.size);
break;
case CR:
in.skip(1);
case LF:
tokenOffsets.add(cache.size);
break lineBuilder;
default:
cache.add((byte) i);
}
}
numTokens = tokenOffsets.size - 1;
tokenOffsetsCache = tokenOffsets.items;
line = new AsciiString(cache.items, 0, cache.size, false);
log.debug("line: {}", line);
if (line.contentEqualsIgnoreCase(EXPANSION)) {
log.trace("skipping row {}: {} is an ignored symbol", index, EXPANSION);
return cacheLine();
}
if (numTokens != numColumns) {
log.warn("skipping row {}: contains {} tokens, expected {}; tokens: {}",
index, numTokens, numColumns, tokens());
return cacheLine();
}
if (log.traceEnabled()) {
final int[] tokenOffsets = this.tokenOffsets.items;
for (int i = 1, j = tokenOffsets[i - 1], s = this.tokenOffsets.size; i < s; i++) {
final int tokenOffset = tokenOffsets[i];
log.trace("{}={}", columnName(i - 1), line.subSequence(j, tokenOffset, false));
j = tokenOffset;
}
}
return tokenOffsets.size - 1;
}
public int numColumns() {
return numColumns;
}
public String[] columnNames() {
final String[] columnNames = new String[numColumns];
for (int i = 0; i < numColumns; i++) columnNames[i] = columnName(i);
return columnNames;
}
public String columnName(int i) {
return columnNames.get(i);
}
public String rowName() {
return parseString(0, "");
}
public int columnId(String columnName) {
return columnIds.get(columnName.toUpperCase(), -1);
}
public int[] columnId(String[] columnNames) {
final int numColumns = columnNames.length;
final int[] columnIds = new int[numColumns];
for (int i = 0; i < numColumns; i++) columnIds[i] = columnId(columnNames[i]);
return columnIds;
}
public int numTokens() {
return numTokens;
}
public AsciiString[] tokens() {
final int numTokens = numTokens();
final AsciiString[] tokens = new AsciiString[numTokens];
for (int i = 0; i < numTokens; i++) tokens[i] = token(i);
return tokens;
}
public AsciiString token(int i) {
final int[] tokenOffsets = tokenOffsetsCache;
return line.subSequence(tokenOffsets[i], tokenOffsets[i + 1]);
}
public byte parseByte(int i, byte defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
final int intValue = line.parseInt(startOffset, endOffset);
final byte result = (byte) intValue;
if (result != intValue) {
throw new NumberFormatException(line.subSequence(startOffset, endOffset, false).toString());
}
return result;
}
public short parseShort(int i, short defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseShort(startOffset, endOffset);
}
public int parseInt(int i, int defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseInt(startOffset, endOffset);
}
public long parseLong(int i, long defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseLong(startOffset, endOffset);
}
public boolean parseBoolean(int i, boolean defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
final int intValue = line.parseInt(startOffset, endOffset);
if ((intValue & 1) != intValue) {
log.warn("boolean exceeds boolean radix at {}:{} (\"{}\", \"{}\"): {}",
index, i, rowName(), columnName(i), intValue);
}
return intValue != 0;
}
public float parseFloat(int i, float defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseFloat(startOffset, endOffset);
}
public double parseDouble(int i, double defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.parseDouble(startOffset, endOffset);
}
public String parseString(int i, String defaultValue) {
final int[] tokenOffsets = tokenOffsetsCache;
final int startOffset = tokenOffsets[i];
final int endOffset = tokenOffsets[i + 1];
if (startOffset >= endOffset) return defaultValue;
return line.toString(tokenOffsets[i], tokenOffsets[i + 1]);
}
}

View File

@ -1,248 +0,0 @@
package com.riiablo.excel2.txt;
import com.riiablo.excel2.Entry;
import com.riiablo.excel2.Excel;
import com.riiablo.excel2.PrimaryKey;
import com.riiablo.excel2.SerializedWith;
import com.riiablo.excel2.serializer.MonStatsSerializer;
import com.riiablo.io.ByteInput;
import com.riiablo.io.ByteOutput;
@Entry(MonStats.Entry.class)
@SerializedWith(MonStatsSerializer.class)
public class MonStats extends Excel<MonStats.Entry, MonStatsSerializer> {
public MonStats() {
super(Entry.class, 1543); // 736 entries
}
@Override
public Entry newEntry() {
return new Entry();
}
@Override
public MonStatsSerializer newSerializer() {
return new MonStatsSerializer();
}
public static class Entry extends Excel.Entry {
@Override
public String toString() {
return NameStr;
}
@PrimaryKey
@Column public String Id;
@Column public int hcIdx;
@Column public String BaseId;
@Column public String NextInClass;
@Column public int TransLvl;
@Column public String NameStr;
@Column public String MonStatsEx;
@Column public String MonProp;
@Column public String MonType;
@Column public String AI;
@Column public String DescStr;
@Column public String Code;
@Column public boolean enabled;
@Column public boolean rangedtype;
@Column public boolean placespawn;
@Column public String spawn;
@Column public int spawnx;
@Column public int spawny;
@Column public String spawnmode;
@Column public String minion1;
@Column public String minion2;
@Column public boolean SetBoss;
@Column public boolean BossXfer;
@Column public int PartyMin;
@Column public int PartyMax;
@Column public int MinGrp;
@Column public int MaxGrp;
@Column public int sparsePopulate;
@Column public int Velocity;
@Column public int Run;
@Column public int Rarity;
@Column(format = "Level%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int Level[];
@Column public String MonSound;
@Column public String UMonSound;
@Column public int threat;
@Column(format = "aidel%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aidel[];
@Column(format = "aidist%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aidist[];
@Column(format = "aip1%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip1[];
@Column(format = "aip2%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip2[];
@Column(format = "aip3%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip3[];
@Column(format = "aip4%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip4[];
@Column(format = "aip5%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip5[];
@Column(format = "aip6%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip6[];
@Column(format = "aip7%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip7[];
@Column(format = "aip8%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int aip8[];
@Column public String MissA1;
@Column public String MissA2;
@Column public String MissS1;
@Column public String MissS2;
@Column public String MissS3;
@Column public String MissS4;
@Column public String MissC;
@Column public String MissSQ;
@Column public int Align;
@Column public boolean isSpawn;
@Column public boolean isMelee;
@Column public boolean npc;
@Column public boolean interact;
@Column public boolean inventory;
@Column public boolean inTown;
@Column public boolean lUndead;
@Column public boolean hUndead;
@Column public boolean demon;
@Column public boolean flying;
@Column public boolean opendoors;
@Column public boolean boss;
@Column public boolean primeevil;
@Column public boolean killable;
@Column public boolean switchai;
@Column public boolean noAura;
@Column public boolean nomultishot;
@Column public boolean neverCount;
@Column public boolean petIgnore;
@Column public boolean deathDmg;
@Column public boolean genericSpawn;
@Column public boolean zoo;
@Column public int SendSkills;
@Column public String Skill1;
@Column public String Sk1mode;
@Column public int Sk1lvl;
@Column public String Skill2;
@Column public String Sk2mode;
@Column public int Sk2lvl;
@Column public String Skill3;
@Column public String Sk3mode;
@Column public int Sk3lvl;
@Column public String Skill4;
@Column public String Sk4mode;
@Column public int Sk4lvl;
@Column public String Skill5;
@Column public String Sk5mode;
@Column public int Sk5lvl;
@Column public String Skill6;
@Column public String Sk6mode;
@Column public int Sk6lvl;
@Column public String Skill7;
@Column public String Sk7mode;
@Column public int Sk7lvl;
@Column public String Skill8;
@Column public String Sk8mode;
@Column public int Sk8lvl;
@Column(format = "Drain%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int Drain[];
@Column(format = "coldeffect%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int coldeffect[];
@Column(format = "ResDm%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResDm[];
@Column(format = "ResMa%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResMa[];
@Column(format = "ResFi%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResFi[];
@Column(format = "ResLi%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResLi[];
@Column(format = "ResCo%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResCo[];
@Column(format = "ResPo%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ResPo[];
@Column public int DamageRegen;
@Column public String SkillDamage;
@Column public boolean noRatio;
@Column public boolean NoShldBlock;
@Column(format = "ToBlock%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int ToBlock[];
@Column public int Crit;
@Column(format = "minHP%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int minHP[];
@Column(format = "maxHP%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int maxHP[];
@Column(format = "AC%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int AC[];
@Column(format = "Exp%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int Exp[];
@Column(format = "A1MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A1MinD[];
@Column(format = "A1MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A1MaxD[];
@Column(format = "A1TH%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A1TH[];
@Column(format = "A2MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A2MinD[];
@Column(format = "A2MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A2MaxD[];
@Column(format = "A2TH%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int A2TH[];
@Column(format = "S1MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int S1MinD[];
@Column(format = "S1MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int S1MaxD[];
@Column(format = "S1TH%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int S1TH[];
@Column public String El1Mode;
@Column public String El1Type;
@Column(format = "El1Pct%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El1Pct[];
@Column(format = "El1MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El1MinD[];
@Column(format = "El1MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El1MaxD[];
@Column(format = "El1Dur%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El1Dur[];
@Column public String El2Mode;
@Column public String El2Type;
@Column(format = "El2Pct%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El2Pct[];
@Column(format = "El2MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El2MinD[];
@Column(format = "El2MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El2MaxD[];
@Column(format = "El2Dur%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El2Dur[];
@Column public String El3Mode;
@Column public String El3Type;
@Column(format = "El3Pct%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El3Pct[];
@Column(format = "El3MinD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El3MinD[];
@Column(format = "El3MaxD%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El3MaxD[];
@Column(format = "El3Dur%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public int El3Dur[];
@Column(format = "TreasureClass1%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public String TreasureClass1[];
@Column(format = "TreasureClass2%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public String TreasureClass2[];
@Column(format = "TreasureClass3%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public String TreasureClass3[];
@Column(format = "TreasureClass4%s", values = {"", "(N)", "(H)"}, endIndex = 3)
public String TreasureClass4[];
@Column public int TCQuestId;
@Column public int TCQuestCP;
@Column public int SplEndDeath;
@Column public boolean SplGetModeChart;
@Column public boolean SplEndGeneric;
@Column public boolean SplClientEnd;
}
public static class Serializer implements com.riiablo.excel2.Serializer<Entry> {
@Override public void readBin(Entry entry, ByteInput in) {}
@Override public void writeBin(Entry entry, ByteOutput out) {}
@Override public boolean equals(Entry e1, Entry e2) { throw new UnsupportedOperationException(); }
@Override public void logErrors(Entry e1, Entry e2) {}
}
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.io.IOException;
import org.junit.BeforeClass;
@ -8,14 +8,14 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.riiablo.RiiabloTest;
import com.riiablo.excel2.txt.MonStats;
import com.riiablo.excel.txt.MonStats;
import com.riiablo.logger.Level;
import com.riiablo.logger.LogManager;
public class BinGeneratorTest extends RiiabloTest {
@BeforeClass
public static void before() {
LogManager.setLevel("com.riiablo.excel2.BinGenerator", Level.TRACE);
LogManager.setLevel("com.riiablo.excel.BinGenerator", Level.TRACE);
}
@Test
@ -26,6 +26,10 @@ public class BinGeneratorTest extends RiiabloTest {
BinGenerator generator = new BinGenerator();
generator.binDir = Gdx.files.absolute(
"C:\\Users\\csmith\\projects\\libgdx\\riiablo\\assets");
generator.generateBin(monstats);
FileHandle excelDir = generator.binDir.child("data/global/excel2");
excelDir.mkdirs();
generator.generateBin(excelDir, monstats);
}
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import java.io.IOException;
import org.junit.Test;
@ -7,14 +7,14 @@ import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.riiablo.RiiabloTest;
import com.riiablo.excel2.txt.MonStats;
import com.riiablo.excel.txt.MonStats;
import com.riiablo.logger.Level;
import com.riiablo.logger.LogManager;
public class ExcelTest extends RiiabloTest {
@org.junit.BeforeClass
public static void before() {
LogManager.setLevel("com.riiablo.excel2.Excel", Level.TRACE);
LogManager.setLevel("com.riiablo.excel.Excel", Level.TRACE);
}
@Test

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import org.junit.BeforeClass;
import org.junit.Test;
@ -12,7 +12,7 @@ import com.riiablo.logger.LogManager;
public class SerializerGeneratorTest extends RiiabloTest {
@BeforeClass
public static void before() {
LogManager.setLevel("com.riiablo.excel2.SerializerGenerator", Level.TRACE);
LogManager.setLevel("com.riiablo.excel.SerializerGenerator", Level.TRACE);
}
@Test
@ -21,12 +21,12 @@ public class SerializerGeneratorTest extends RiiabloTest {
generator.init();
generator.sourceDir = Gdx.files.absolute(
"C:\\Users\\csmith\\projects\\libgdx\\riiablo"
+ "\\core\\src\\main\\java\\com\\riiablo\\excel2\\txt");
+ "\\core\\src\\main\\java\\com\\riiablo\\excel\\txt");
generator.serializerDir = Gdx.files.absolute(
"C:\\Users\\csmith\\projects\\libgdx\\riiablo"
+ "\\core\\src\\main\\java");
generator.sourcePackage = "com.riiablo.excel2.txt";
generator.serializerPackage = "com.riiablo.excel2.serializer";
generator.sourcePackage = "com.riiablo.excel.txt";
generator.serializerPackage = "com.riiablo.excel.serializer";
generator.generateSerializers();
}
}

View File

@ -1,4 +1,4 @@
package com.riiablo.excel2;
package com.riiablo.excel;
import com.squareup.javapoet.JavaFile;
import java.io.IOException;
@ -6,7 +6,7 @@ import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TestName;
import com.riiablo.excel2.txt.MonStats;
import com.riiablo.excel.txt.MonStats;
public class SerializerSourceGeneratorTest {
@Rule

View File

@ -1,7 +1,7 @@
package com.riiablo.excel;
import java.io.IOException;
import org.junit.BeforeClass;
import org.junit.Assert;
import org.junit.Test;
import com.badlogic.gdx.Gdx;
@ -12,15 +12,41 @@ import com.riiablo.logger.Level;
import com.riiablo.logger.LogManager;
public class TxtParserTest extends RiiabloTest {
@BeforeClass
@org.junit.BeforeClass
public static void before() {
LogManager.setLevel("com.riiablo.excel.TxtParser", Level.TRACE);
}
@Test
public void parse_monstats_header() throws IOException {
FileHandle monstats = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(monstats);
String[] columnNames = parser.getColumnNames();
public void parse_monstats_columns() throws IOException {
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser.parse(handle.read());
}
@Test
public void parse_monstats_first() throws IOException {
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
}
@Test
public void parse_monstats_first_2() throws IOException {
LogManager.setLevel("com.riiablo.excel", Level.DEBUG);
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
parser.cacheLine();
LogManager.setLevel("com.riiablo.excel", Level.TRACE);
}
@Test
public void parse_monstats_parseInt() throws IOException {
LogManager.setLevel("com.riiablo.excel", Level.DEBUG);
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
Assert.assertEquals(0, parser.parseInt(1, -1));
LogManager.setLevel("com.riiablo.excel", Level.TRACE);
}
}

View File

@ -1,52 +0,0 @@
package com.riiablo.excel2;
import java.io.IOException;
import org.junit.Assert;
import org.junit.Test;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.riiablo.RiiabloTest;
import com.riiablo.logger.Level;
import com.riiablo.logger.LogManager;
public class TxtParserTest extends RiiabloTest {
@org.junit.BeforeClass
public static void before() {
LogManager.setLevel("com.riiablo.excel2.TxtParser", Level.TRACE);
}
@Test
public void parse_monstats_columns() throws IOException {
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser.parse(handle.read());
}
@Test
public void parse_monstats_first() throws IOException {
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
}
@Test
public void parse_monstats_first_2() throws IOException {
LogManager.setLevel("com.riiablo.excel2", Level.DEBUG);
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
parser.cacheLine();
LogManager.setLevel("com.riiablo.excel2", Level.TRACE);
}
@Test
public void parse_monstats_parseInt() throws IOException {
LogManager.setLevel("com.riiablo.excel2", Level.DEBUG);
FileHandle handle = Gdx.files.internal("test/monstats.txt");
TxtParser parser = TxtParser.parse(handle.read());
parser.cacheLine();
Assert.assertEquals(0, parser.parseInt(1, -1));
LogManager.setLevel("com.riiablo.excel2", Level.TRACE);
}
}