fy-convertor
Version:
Convert excel/xml/json/bin/protocl/ts/as ...
262 lines • 12 kB
JavaScript
import fs from "fs-extra";
import path from "path";
import { ProtocolStructParser } from "./ProtocolStructParser.js";
import { Byte } from "./Byte.js";
import { toolchain } from "../tools/toolchain.js";
var EBaseType;
(function (EBaseType) {
EBaseType[EBaseType["char"] = 0] = "char";
EBaseType[EBaseType["uchar"] = 1] = "uchar";
EBaseType[EBaseType["byte"] = 2] = "byte";
EBaseType[EBaseType["short"] = 3] = "short";
EBaseType[EBaseType["ushort"] = 4] = "ushort";
EBaseType[EBaseType["int"] = 5] = "int";
EBaseType[EBaseType["uint"] = 6] = "uint";
EBaseType[EBaseType["longlong"] = 7] = "longlong";
EBaseType[EBaseType["ulonglong"] = 8] = "ulonglong";
EBaseType[EBaseType["string"] = 9] = "string";
EBaseType[EBaseType["max"] = 10] = "max";
})(EBaseType || (EBaseType = {}));
;
var ETypeFlagV1;
(function (ETypeFlagV1) {
ETypeFlagV1[ETypeFlagV1["has_count"] = 268435456] = "has_count";
ETypeFlagV1[ETypeFlagV1["has_ver"] = 536870912] = "has_ver";
ETypeFlagV1[ETypeFlagV1["has_refer"] = 1073741824] = "has_refer";
ETypeFlagV1[ETypeFlagV1["has_select"] = 2147483648] = "has_select";
ETypeFlagV1[ETypeFlagV1["mask"] = 268435455] = "mask";
})(ETypeFlagV1 || (ETypeFlagV1 = {}));
var ETypeFlagV2;
(function (ETypeFlagV2) {
ETypeFlagV2[ETypeFlagV2["has_count"] = 16777216] = "has_count";
ETypeFlagV2[ETypeFlagV2["has_ver"] = 33554432] = "has_ver";
ETypeFlagV2[ETypeFlagV2["has_refer"] = 67108864] = "has_refer";
ETypeFlagV2[ETypeFlagV2["has_select"] = 134217728] = "has_select";
ETypeFlagV2[ETypeFlagV2["safeprintf"] = 268435456] = "safeprintf";
ETypeFlagV2[ETypeFlagV2["mask"] = 16777215] = "mask";
})(ETypeFlagV2 || (ETypeFlagV2 = {}));
const FIELD_NAME_MAX_LEN = 2048;
export class Xml2CSBytes {
static write(filePath) {
class NameMgr {
static names = [];
static getNameIdx(name) {
let nameIdx = this.names.indexOf(name);
if (nameIdx < 0) {
this.names.push(name);
nameIdx = this.names.length - 1;
}
return nameIdx;
}
}
class TypeMgr {
static ins = new TypeMgr();
types = [];
version = 1;
constructor() {
if (toolchain.projCfg.xml2protocol.useCSBytes === 'YES_V2') {
this.version = 2;
}
console.log('Xml2CSBytes will build ss.bytes with version ' + this.version);
for (let i = 0; i < EBaseType.max; i++) {
this.types.push({ name: EBaseType[i], offset: 0, type: "base" });
}
}
getType(type) {
type = this.convertType(type);
let t = this.types.find(i => i.name == type);
if (t)
return this.types.indexOf(t);
this.types.push({ name: type, offset: -1, type: "struct" });
return this.types.length - 1;
}
;
setTypeOffset(type, offset) {
type = this.convertType(type);
let t = this.types.find(i => i.name == type);
console.assert(t.offset < 0);
t.offset = offset;
}
isStructType(type) {
type = this.convertType(type);
let t = this.types.find(i => i.name == type);
return t.type == "struct";
}
serializedType(type) {
type = this.convertType(type);
let t = this.types.find(i => i.name == type);
return t.offset >= 0;
}
convertType(type) { return type == "String" ? "string" : type; }
}
function getMacroValue(value) {
if (!isNaN(Number(value)))
return Number(value);
let rt = ProtocolStructParser.Instance.getMacro(value)?._attributes.value;
if (!isNaN(Number(rt)))
return Number(rt);
console.error("failed! 未找到宏定义:" + value);
process.exit(1);
}
let writer = new Byte(new ArrayBuffer(5 * 1024 * 1024));
function writeStructType(st) {
const clientUsedPick = st.options?.clientUsed_pick;
//writer.writeString(st._attributes.name);
let valuemapPos = 0;
let isUnion = st._attributes.class == "union";
let valueAndFieldMap = [];
if (isUnion) {
let fieldCount = 0;
for (let entry of st.entries) {
if (entry._attributes.value) {
if (clientUsedPick) {
// 只有启用了clientUsed的字段才写入
const entrySt = ProtocolStructParser.Instance.getStructDef(entry._attributes.type);
if (entrySt?.options?.clientUsed) {
fieldCount++;
}
}
else {
fieldCount++;
}
}
}
writer.writeUint8(1); // union flag
writer.writeUint32(fieldCount);
valuemapPos = writer.Pos;
writer.skip(fieldCount * 2 * 4); // 用来存放value哈希过后的bucket的节点个数和偏移量, {bucketNodesCount, bucketOffset}[]
}
else {
writer.writeUint8(0); // struct flag
writer.writeUint32(st.entries.length);
}
let attTypes = [];
for (let entry of st.entries) {
let att = entry._attributes;
if (isUnion) {
if (!att.value)
continue;
if (clientUsedPick) {
// 只有启用了clientUsed的字段才写入
const entrySt = ProtocolStructParser.Instance.getStructDef(entry._attributes.type);
if (!entrySt?.options?.clientUsed) {
continue;
}
}
}
const ETypeFlag = TypeMgr.ins.version > 1 ? ETypeFlagV2 : ETypeFlagV1;
let nameIdx = NameMgr.getNameIdx(att.name);
let type = TypeMgr.ins.getType(att.type);
if (type > ETypeFlag.mask) {
throw new Error('type overflow!');
}
if (TypeMgr.ins.version > 1) {
if (att.safeprintf)
type = type | ETypeFlagV2.safeprintf;
}
if (isUnion) {
let count = 0;
if (att.size)
count = getMacroValue(att.size);
if (att.count)
count = getMacroValue(att.count);
if (count > 0xffff) {
console.log("failed! 数组太长:" + st._attributes.name + "." + att.name);
process.exit(1);
}
valueAndFieldMap.push({ value: getMacroValue(att.value), fieldType: type, fieldNameIdx: (count << 16) | nameIdx });
}
else {
writer.writeUint16(nameIdx); // write name_idx
if (att.version)
type = type | ETypeFlag.has_ver;
if (att.count || att.size)
type = type | ETypeFlag.has_count;
if (att.refer)
type = type | ETypeFlag.has_refer;
if (att.select)
type = type | ETypeFlag.has_select;
writer.writeUint32(type); // write type
if (att.version)
writer.writeUint32(Number(att.version));
if (att.count) {
writer.writeUint32(getMacroValue(att.count));
}
;
if (att.size) {
writer.writeUint32(getMacroValue(att.size));
}
if (att.refer) {
writer.writeUint16(NameMgr.getNameIdx(att.refer));
}
if (att.select) {
writer.writeUint16(NameMgr.getNameIdx(att.select));
}
}
attTypes.push(att.type);
}
for (let attType of attTypes) {
if (TypeMgr.ins.isStructType(attType) && !TypeMgr.ins.serializedType(attType)) {
TypeMgr.ins.setTypeOffset(attType, writer.Pos);
writeStructType(ProtocolStructParser.Instance.getStructDef(attType));
}
}
if (isUnion) {
valueAndFieldMap.sort((a, b) => a.value - b.value);
// 生成hash的bucket节点
let bucketsOffset = [];
for (let bucketIdx = 0, size = valueAndFieldMap.length; bucketIdx < size; bucketIdx++) {
let bucketNodes = [];
for (let vf of valueAndFieldMap) {
if ((vf.value % size) == bucketIdx) {
bucketNodes.push({ value: vf.value, fieldType: vf.fieldType, fieldNameIdx: vf.fieldNameIdx });
}
}
bucketsOffset.push({ bucketNodesCount: bucketNodes.length, bucketOffset: writer.Pos });
for (let node of bucketNodes) {
writer.writeUint32(node.value);
writer.writeUint32(node.fieldType);
writer.writeUint32(node.fieldNameIdx);
}
}
// 回填 {bucketNodesCount, bucketOffset}[]
writer.resetPos(valuemapPos);
for (let vf of bucketsOffset) {
writer.writeUint32(vf.bucketNodesCount);
writer.writeUint32(vf.bucketOffset);
}
writer.restorePos();
}
}
//写入文件头
writer.writeUint32(TypeMgr.ins.version); // 文件版本
writer.writeUint32(getMacroValue('VERSION')); // 协议版本
let typesBytesSizePos = writer.Pos;
writer.skip(4); // 所有类型的字节长度
let headSize = writer.Pos;
const bodyDef = ProtocolStructParser.Instance.getStructDef("CSMsgBody");
writeStructType(bodyDef);
let typesEndPos = writer.Pos;
// 回填所有类型的字节长度
writer.resetPos(typesBytesSizePos);
writer.writeUint32(typesEndPos - headSize);
writer.restorePos();
// 写入字段名names
writer.writeUint16(NameMgr.names.length); // name个数
for (let name of NameMgr.names) {
if ((name.length + 1) > FIELD_NAME_MAX_LEN)
throw new Error("协议字段名超长, 字段名" + name);
writer.writeUTF8String(name, false);
}
// 写入structtype在文件中的偏移量
writer.writeUint16(TypeMgr.ins.types.length); // type个数
for (let type of TypeMgr.ins.types) {
writer.writeUint32(type.offset);
}
if (!fs.existsSync(path.dirname(filePath))) {
fs.mkdirSync(path.dirname(filePath));
}
fs.writeFileSync(filePath, writer.NewBuffer, { flag: "w" });
}
}
//# sourceMappingURL=Xml2CSBytes.js.map