/**
*
*/
package com.owent.xresloader;
import com.owent.xresloader.data.dst.*;
import com.owent.xresloader.data.src.DataSrcExcel;
import com.owent.xresloader.data.src.DataSrcImpl;
import com.owent.xresloader.engine.IdentifyEngine;
import com.owent.xresloader.scheme.SchemeConf;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static com.owent.xresloader.ProgramOptions.FileType.BIN;
/**
* @author owentou
*/
public class main {
static private String endl = "\n";
private static DataDstImpl get_out_desc(DataDstImpl proto_desc) {
DataDstImpl outDesc = null;
switch (ProgramOptions.getInstance().outType) {
case BIN:
outDesc = proto_desc;
break;
case LUA:
outDesc = new DataDstLua();
outDesc = outDesc.init() ? outDesc : null;
break;
case MSGPACK:
outDesc = new DataDstMsgPack();
outDesc = outDesc.init() ? outDesc : null;
break;
case JSON:
outDesc = new DataDstJson();
outDesc = outDesc.init() ? outDesc : null;
break;
case XML:
outDesc = new DataDstXml();
outDesc = outDesc.init() ? outDesc : null;
break;
case JAVASCRIPT:
outDesc = new DataDstJavascript();
outDesc = outDesc.init() ? outDesc : null;
break;
default:
ProgramOptions.getLoger().error("output type \"%s\" invalid", ProgramOptions.getInstance().outType.toString());
break;
}
return outDesc;
}
private static int print_const_data() {
// 1. 协议描述文件
DataDstImpl protoDesc = null;
switch (ProgramOptions.getInstance().protocol) {
case PROTOBUF:
protoDesc = new DataDstPb();
break;
default:
ProgramOptions.getLoger().error("protocol type \"%s\" invalid", ProgramOptions.getInstance().protocol.toString());
break;
}
if (null == protoDesc)
return 1;
DataDstImpl outDesc = get_out_desc(protoDesc);
if (null == outDesc)
return 1;
HashMap<String, Object> enum_data = protoDesc.buildConst();
if (null == enum_data) {
ProgramOptions.getLoger().error("protocol desc \"%s\" init and build const values failed", ProgramOptions.getInstance().protocol.toString());
return 1;
}
try {
String filePath = ProgramOptions.getInstance().constPrint;
if(!IdentifyEngine.isAbsPath(filePath))
filePath = ProgramOptions.getInstance().outputDirectory + '/' + filePath;
OutputStream fos = new FileOutputStream(filePath, false);
byte[] data = outDesc.dumpConst(enum_data);
if (null != data) {
fos.write(data);
} else {
ProgramOptions.getLoger().error("write const data to file \"%s\" failed, output type invalid.", ProgramOptions.getInstance().constPrint);
return 1;
}
} catch (java.io.IOException e) {
ProgramOptions.getLoger().error("write data to file \"%s\" failed", ProgramOptions.getInstance().constPrint);
return 1;
}
ProgramOptions.getLoger().info(
"write const data to \"%s\" success.(charset: %s)",
ProgramOptions.getInstance().constPrint,
SchemeConf.getInstance().getKey().getEncoding()
);
return 0;
}
private static int build_group(String[] args) {
int ret = ProgramOptions.getInstance().init(args);
if (ret < 0) {
return 1;
} else if (ret > 0) {
return 0;
}
SchemeConf.getInstance().reset();
// 特殊流程,常量打印
if (false == ProgramOptions.getInstance().constPrint.isEmpty()) {
return print_const_data();
}
ret = SchemeConf.getInstance().initScheme();
if (ret < 0) {
return 1;
}
// 读入数据表 & 协议编译
int failed_count = 0;
for (int i = 0; i < ProgramOptions.getInstance().dataSourceMetas.length; ++ i) {
String sn = ProgramOptions.getInstance().dataSourceMetas[i];
// 0. 清理
SchemeConf.getInstance().getMacroSource().clear();
SchemeConf.getInstance().getDataSource().clear();
// 1. 描述信息
if (false == SchemeConf.getInstance().getScheme().load_scheme(sn)) {
sn = String.join(" ", ProgramOptions.getInstance().dataSourceMetas);
ProgramOptions.getLoger().error("convert from \"%s\" failed", sn);
++ failed_count;
continue;
}
// 命令行模式下dataSourceType为默认值,也就是BIN
if (false == SchemeConf.getInstance().getScheme().isSupportMultipleScheme()) {
// 命令行输入模式只触发一次,并且scheme名称改成所有配置的和
if (i > 0) {
break;
} else {
sn = String.join(" ", ProgramOptions.getInstance().dataSourceMetas);
}
}
// 重新组织sn
StringBuilder descBuilder = new StringBuilder();
for(SchemeConf.DataInfo di: SchemeConf.getInstance().getDataSource()) {
if (descBuilder.length() > 0) {
descBuilder.append(',');
}
descBuilder.append(di.file_path);
if (!di.file_path.contains(di.table_name)) {
descBuilder.append('|');
descBuilder.append(di.table_name);
}
}
sn = descBuilder.toString();
// 2. 数据工作簿
Class ds_clazz = DataSrcExcel.class;
DataSrcImpl ds = DataSrcImpl.create(ds_clazz);
if (null == ds) {
ProgramOptions.getLoger().error("create data source class \"%s\" failed", ds_clazz.getName());
++ failed_count;
continue;
}
ret = ds.init();
if (ret < 0) {
ProgramOptions.getLoger().error("init data source class \"%s\" failed", ds_clazz.getName());
++ failed_count;
continue;
}
// 3. 协议描述文件
DataDstImpl protoDesc = null;
switch (ProgramOptions.getInstance().protocol) {
case PROTOBUF:
protoDesc = new DataDstPb();
break;
default:
ProgramOptions.getLoger().error("protocol type \"%s\" invalid", ProgramOptions.getInstance().protocol.toString());
++ failed_count;
break;
}
if (null == protoDesc)
continue;
if (false == protoDesc.init()) {
ProgramOptions.getLoger().error("protocol desc \"%s\" init failed", ProgramOptions.getInstance().protocol.toString());
++ failed_count;
continue;
}
// 4. 输出类型
DataDstImpl outDesc = get_out_desc(protoDesc);
if (null == outDesc)
continue;
ProgramOptions.getLoger().trace(
"convert from \"%s\" to \"%s\" started (protocol=%s) ...",
sn,
SchemeConf.getInstance().getOutputFile(), SchemeConf.getInstance().getProtoName()
);
try {
String filePath = SchemeConf.getInstance().getOutputFile();
if (!IdentifyEngine.isAbsPath(filePath))
filePath = ProgramOptions.getInstance().outputDirectory + '/' + filePath;
OutputStream fos = new FileOutputStream(filePath, false);
byte[] data = outDesc.build(protoDesc);
if (null != data) {
fos.write(data);
}
} catch (com.owent.xresloader.data.err.ConvException e) {
ProgramOptions.getLoger().error("convert data failed.%s > %s%s > %s",
endl, String.join(" ", args),
endl, e.getMessage()
);
++ failed_count;
continue;
} catch (java.io.IOException e) {
ProgramOptions.getLoger().error("write data to file \"%s\" failed", SchemeConf.getInstance().getOutputFile());
++ failed_count;
continue;
}
ProgramOptions.getLoger().info(
"convert from \"%s\" to \"%s\" success.(charset: %s)",
sn,
SchemeConf.getInstance().getOutputFile(),
SchemeConf.getInstance().getKey().getEncoding()
);
}
return failed_count;
}
// 因为所有的参数除了特定名字外都是文件或目录的路径,而跨平台的路径是不能包含双引号的,所以为了简单起见,就不需要“的转义功能了
private static Pattern pick_args_rule = Pattern.compile("('[^']*')|(\"[^\"]*\")|(\\S+)", Pattern.MULTILINE | Pattern.CASE_INSENSITIVE);
private static String[] pick_stdin_args(Scanner jin) {
String[] ret = null;
if (jin.hasNextLine()) {
Matcher rem = pick_args_rule.matcher(jin.nextLine());
LinkedList<String> res = new LinkedList<String>();
while(rem.find()) {
String item = rem.group();
if (item.charAt(0) == '"' && item.charAt(item.length() - 1) == '"') {
if (item.length() > 2) {
item = item.substring(1, item.length() - 1);
} else {
item = "";
}
// 如果需要转义功能的话
} else if (item.charAt(0) == '\'' && item.charAt(item.length() - 1) == '\'') {
if (item.length() > 2) {
item = item.substring(1, item.length() - 1);
} else {
item = "";
}
}
if (item.length() > 0) {
res.add(item);
}
}
ret = new String[res.size()];
for(int i = 0; !res.isEmpty(); ++ i, res.removeFirst()) {
ret[i] = res.getFirst();
}
}
return ret;
}
/**
* @param args
*/
public static void main(String[] args) {
endl = System.getProperty("line.separator", "\n");
// 先尝试根据传入参数转表
int ret_code = build_group(args);
// 再尝试使用标准输入来批量转表
if (ProgramOptions.getInstance().enableStdin) {
String[] stdin_args = null;
Scanner jin = new Scanner(System.in);
while (null != (stdin_args = pick_stdin_args(jin))) {
if (stdin_args.length > 0) {
ret_code += build_group(stdin_args);
}
}
}
// 退出码为失败的任务个数,用以外部捕获转换失败
System.exit(ret_code);
}
}