mirror of
https://github.com/SteamAutoCracks/DepotDownloaderMod.git
synced 2026-02-12 21:00:57 +01:00
Reworked EmitClassSerializer/Deserializer to use BinaryReader/Writer. Refactored root parsing logic to support multiple projects.
532 lines
19 KiB
C#
532 lines
19 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
|
|
namespace SteamLanguageParser
|
|
{
|
|
class JavaGen : ICodeGen
|
|
{
|
|
private static Dictionary<String, String> readerTypeMap = new Dictionary<String, String>
|
|
{
|
|
{"byte", ""},
|
|
{"short", "Short"},
|
|
{"int", "Int"},
|
|
{"long", "Long"},
|
|
};
|
|
|
|
public void EmitNamespace(StringBuilder sb, bool end, string nspace)
|
|
{
|
|
if (end)
|
|
{
|
|
sb.AppendLine("}");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine("package net.steam3;");
|
|
sb.AppendLine("import java.nio.*;");
|
|
sb.AppendLine("import steamkit.steam3.SteamMessages.*;");
|
|
sb.AppendLine("import steamkit.util.MsgUtil;");
|
|
sb.AppendLine("import com.google.protobuf.InvalidProtocolBufferException;");
|
|
|
|
sb.AppendLine();
|
|
|
|
sb.AppendLine("public final class SteamLanguage {");
|
|
}
|
|
}
|
|
|
|
public void EmitSerialBase(StringBuilder sb, int level, bool supportsGC)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
sb.AppendLine(padding + "public interface ISteamSerializable");
|
|
sb.AppendLine(padding + "{");
|
|
sb.AppendLine(padding + "\tpublic ByteBuffer serialize();");
|
|
sb.AppendLine(padding + "\tpublic void deserialize( ByteBuffer buffer ) throws InvalidProtocolBufferException;");
|
|
sb.AppendLine(padding + "}");
|
|
|
|
sb.AppendLine(padding + "public interface ISteamSerializableHeader extends ISteamSerializable");
|
|
sb.AppendLine(padding + "{");
|
|
sb.AppendLine(padding + "\tpublic void SetEMsg( EMsg msg );");
|
|
sb.AppendLine(padding + "}");
|
|
|
|
sb.AppendLine(padding + "public interface ISteamSerializableMessage extends ISteamSerializable");
|
|
sb.AppendLine(padding + "{");
|
|
sb.AppendLine(padding + "\tpublic EMsg GetEMsg();");
|
|
sb.AppendLine(padding + "}");
|
|
|
|
sb.AppendLine();
|
|
}
|
|
|
|
public string EmitType(Symbol sym)
|
|
{
|
|
if (sym is WeakSymbol)
|
|
{
|
|
WeakSymbol wsym = sym as WeakSymbol;
|
|
|
|
return CodeGenerator.GetUnsignedType(wsym.Identifier);
|
|
}
|
|
else if (sym is StrongSymbol)
|
|
{
|
|
StrongSymbol ssym = sym as StrongSymbol;
|
|
|
|
if (ssym.Prop == null)
|
|
{
|
|
return ssym.Class.Name;
|
|
}
|
|
else
|
|
{
|
|
return ssym.Class.Name + "." + ssym.Prop.Name;
|
|
}
|
|
}
|
|
|
|
return "INVALID";
|
|
}
|
|
|
|
public string GetUpperName(string name)
|
|
{
|
|
return name.Substring(0, 1).ToUpper() + name.Remove(0, 1);
|
|
}
|
|
|
|
public void EmitNode(Node n, StringBuilder sb, int level)
|
|
{
|
|
if (n is ClassNode)
|
|
{
|
|
EmitClassNode(n as ClassNode, sb, level);
|
|
}
|
|
else if (n is EnumNode)
|
|
{
|
|
EmitEnumNode(n as EnumNode, sb, level);
|
|
}
|
|
}
|
|
|
|
private void EmitEnumNode(EnumNode enode, StringBuilder sb, int level)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
sb.AppendLine(padding + "public enum " + enode.Name);
|
|
sb.AppendLine(padding + "{");
|
|
|
|
string lastValue = "0";
|
|
|
|
foreach (PropNode prop in enode.childNodes)
|
|
{
|
|
lastValue = EmitType(prop.Default);
|
|
sb.AppendLine(padding + "\t" + prop.Name + "(" + lastValue + "),");
|
|
}
|
|
|
|
int maxint = Int32.Parse(lastValue) + 1;
|
|
|
|
sb.AppendLine(padding + "\tMax(" + maxint + ");");
|
|
|
|
sb.AppendLine();
|
|
sb.AppendLine(padding + "\tprivate int code;");
|
|
|
|
sb.AppendLine(padding + "\tprivate " + enode.Name + "( int c ) { code = c; }");
|
|
|
|
sb.AppendLine(padding + "\tpublic int getCode() {");
|
|
sb.AppendLine(padding + "\t\treturn code;");
|
|
sb.AppendLine(padding + "\t}");
|
|
|
|
sb.AppendLine(padding + "\tpublic static " + enode.Name + " lookup( int code ) {");
|
|
sb.AppendLine(padding + "\t\tfor ( " + enode.Name + " x : values() ) {");
|
|
sb.AppendLine(padding + "\t\t\tif( x.getCode() == code ) return x;");
|
|
sb.AppendLine(padding + "\t\t}");
|
|
sb.AppendLine(padding + "\t\treturn Invalid;");
|
|
sb.AppendLine(padding + "\t}");
|
|
|
|
sb.AppendLine(padding + "}");
|
|
}
|
|
|
|
private void EmitClassNode(ClassNode cnode, StringBuilder sb, int level)
|
|
{
|
|
EmitClassDef(cnode, sb, level, false);
|
|
|
|
EmitClassIdentity(cnode, sb, level + 1);
|
|
|
|
int baseSize = EmitClassProperties(cnode, sb, level + 1);
|
|
EmitClassConstructor(cnode, sb, level + 1);
|
|
|
|
EmitClassSerializer(cnode, sb, level + 1, baseSize);
|
|
EmitClassDeserializer(cnode, sb, level + 1, baseSize);
|
|
|
|
EmitClassDef(cnode, sb, level, true);
|
|
}
|
|
|
|
private void EmitClassDef(ClassNode cnode, StringBuilder sb, int level, bool end)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
if (end)
|
|
{
|
|
sb.AppendLine(padding + "}");
|
|
sb.AppendLine();
|
|
return;
|
|
}
|
|
|
|
string parent = "ISteamSerializable";
|
|
|
|
if (cnode.Ident != null)
|
|
{
|
|
parent = "ISteamSerializableMessage";
|
|
}
|
|
else if (cnode.Name.Contains("Hdr"))
|
|
{
|
|
parent = "ISteamSerializableHeader";
|
|
}
|
|
|
|
sb.AppendLine(padding + "public static class " + cnode.Name + " implements " + parent);
|
|
sb.AppendLine(padding + "{");
|
|
}
|
|
|
|
private void EmitClassIdentity(ClassNode cnode, StringBuilder sb, int level)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
if (cnode.Ident != null)
|
|
{
|
|
sb.AppendLine(padding + "public EMsg GetEMsg() { return " + EmitType(cnode.Ident) + "; }");
|
|
sb.AppendLine();
|
|
}
|
|
else if (cnode.Name.Contains("Hdr"))
|
|
{
|
|
sb.AppendLine(padding + "public void SetEMsg( EMsg msg ) { this.msg = msg; }");
|
|
sb.AppendLine();
|
|
}
|
|
}
|
|
|
|
private int EmitClassProperties(ClassNode cnode, StringBuilder sb, int level)
|
|
{
|
|
StringBuilder sbAccessors = new StringBuilder();
|
|
|
|
string padding = new String('\t', level);
|
|
int baseClassSize = 0;
|
|
|
|
if (cnode.Parent != null)
|
|
{
|
|
sb.AppendLine(padding + "private " + EmitType(cnode.Parent) + " header;");
|
|
}
|
|
|
|
foreach (PropNode prop in cnode.childNodes)
|
|
{
|
|
string typestr = EmitType(prop.Type);
|
|
string propName = prop.Name;
|
|
|
|
if (prop.Flags != null && prop.Flags == "const")
|
|
{
|
|
sb.AppendLine(padding + "public static final " + typestr + " " + propName + " = " + EmitType(prop.Default) + ";");
|
|
continue;
|
|
}
|
|
|
|
int size = CodeGenerator.GetTypeSize(prop);
|
|
baseClassSize += size;
|
|
|
|
sb.AppendLine( padding + "// Static size: " + size);
|
|
|
|
int temp;
|
|
if (!String.IsNullOrEmpty(prop.FlagsOpt) && Int32.TryParse(prop.FlagsOpt, out temp))
|
|
{
|
|
typestr += "[]";
|
|
}
|
|
|
|
sb.AppendLine(padding + "private " + typestr + " " + propName + ";");
|
|
|
|
string upname = GetUpperName(propName);
|
|
sbAccessors.AppendLine(padding + "public " + typestr + " get" + upname + "() { return " + propName + "; }");
|
|
sbAccessors.AppendLine(padding + "public void set" + upname + "( " + typestr + " value ) { " + propName + " = value; }");
|
|
}
|
|
|
|
sb.AppendLine();
|
|
|
|
sb.Append(sbAccessors.ToString());
|
|
sb.AppendLine();
|
|
|
|
return baseClassSize;
|
|
}
|
|
|
|
private void EmitClassConstructor(ClassNode cnode, StringBuilder sb, int level)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
sb.AppendLine(padding + "public " + cnode.Name + "()");
|
|
sb.AppendLine(padding + "{");
|
|
|
|
if (cnode.Parent != null)
|
|
{
|
|
sb.AppendLine(padding + "\tHeader = new " + EmitType(cnode.Parent) + "();");
|
|
sb.AppendLine(padding + "\tHeader.Msg = GetEMsg();");
|
|
}
|
|
|
|
foreach (PropNode prop in cnode.childNodes)
|
|
{
|
|
Symbol defsym = prop.Default;
|
|
string defflags = prop.Flags;
|
|
|
|
string symname = prop.Name;
|
|
string ctor = EmitType(defsym);
|
|
string proptype = EmitType(prop.Type);
|
|
|
|
if (defflags != null && defflags == "proto")
|
|
{
|
|
ctor = proptype + ".getDefaultInstance()";
|
|
}
|
|
else if (defsym == null)
|
|
{
|
|
if (!String.IsNullOrEmpty(prop.FlagsOpt))
|
|
{
|
|
ctor = "new " + EmitType(prop.Type) + "[" + CodeGenerator.GetTypeSize(prop) + "]";
|
|
}
|
|
else
|
|
{
|
|
ctor = "0";
|
|
}
|
|
}
|
|
else if (proptype == "byte")
|
|
{
|
|
ctor = "(byte)" + ctor;
|
|
}
|
|
|
|
if (defflags != null && defflags == "steamidmarshal")
|
|
{
|
|
symname = prop.Name;
|
|
}
|
|
else if (defflags != null && defflags == "const")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
sb.AppendLine(padding + "\t" + symname + " = " + ctor + ";");
|
|
}
|
|
|
|
sb.AppendLine(padding + "}");
|
|
}
|
|
|
|
private void EmitClassSerializer(ClassNode cnode, StringBuilder sb, int level, int baseSize)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
sb.AppendLine();
|
|
sb.AppendLine(padding + "public ByteBuffer serialize()");
|
|
sb.AppendLine(padding + "{");
|
|
|
|
|
|
// first emit variable length members
|
|
List<String> varLengthProps = new List<String>();
|
|
varLengthProps.Add(baseSize.ToString());
|
|
|
|
if (cnode.Parent != null)
|
|
{
|
|
sb.AppendLine(padding + "\tByteBuffer bufHeader = Header.serialize();");
|
|
varLengthProps.Add("bufHeader.limit()");
|
|
|
|
sb.AppendLine();
|
|
}
|
|
|
|
foreach (PropNode prop in cnode.childNodes)
|
|
{
|
|
string typestr = EmitType(prop.Type);
|
|
int size = CodeGenerator.GetTypeSize(prop);
|
|
|
|
if (size == 0)
|
|
{
|
|
if (prop.Flags != null && prop.Flags == "proto")
|
|
{
|
|
sb.AppendLine(padding + "\tByteBuffer buf" + GetUpperName(prop.Name) + " = " + prop.Name + ".toByteString().asReadOnlyByteBuffer();");
|
|
|
|
if (prop.FlagsOpt != null)
|
|
{
|
|
sb.AppendLine(padding + "\t" + prop.FlagsOpt + " = buf" + GetUpperName(prop.Name) + ".limit();");
|
|
}
|
|
|
|
if (baseSize == 0)
|
|
{
|
|
// early exit
|
|
sb.AppendLine(padding + "\treturn buf" + GetUpperName(prop.Name) + ";");
|
|
sb.AppendLine(padding + "}");
|
|
return;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(padding + "\tByteBuffer buf" + GetUpperName(prop.Name) + " = " + GetUpperName(prop.Name) + ".serialize();");
|
|
}
|
|
|
|
varLengthProps.Add( "buf" + GetUpperName(prop.Name) + ".limit()" );
|
|
}
|
|
}
|
|
|
|
sb.AppendLine(padding + "\tByteBuffer buffer = ByteBuffer.allocate( " + String.Join(" + ", varLengthProps.ToArray()) + " );");
|
|
sb.AppendLine(padding + "\tbuffer.order( ByteOrder.LITTLE_ENDIAN );");
|
|
sb.AppendLine();
|
|
|
|
if (cnode.Parent != null)
|
|
{
|
|
sb.AppendLine(padding + "\tbuffer.put( bufHeader );");
|
|
}
|
|
|
|
// next emit writers
|
|
foreach (PropNode prop in cnode.childNodes)
|
|
{
|
|
string typestr = EmitType(prop.Type);
|
|
string typecast = "";
|
|
string propName = prop.Name;
|
|
int size = CodeGenerator.GetTypeSize(prop);
|
|
|
|
if (prop.Type is StrongSymbol && ((StrongSymbol)prop.Type).Class is EnumNode)
|
|
{
|
|
EnumNode enode = ((StrongSymbol)prop.Type).Class as EnumNode;
|
|
|
|
if (enode.Type is WeakSymbol)
|
|
typecast = "(" + ((WeakSymbol)enode.Type).Identifier + ")";
|
|
else
|
|
typecast = "(int)";
|
|
|
|
propName = propName + ".getCode()";
|
|
}
|
|
|
|
if (!readerTypeMap.ContainsKey(typestr))
|
|
{
|
|
typestr = CodeGenerator.GetTypeOfSize(size, SupportsUnsignedTypes());
|
|
}
|
|
|
|
if (prop.Flags != null)
|
|
{
|
|
if (prop.Flags == "steamidmarshal")
|
|
{
|
|
|
|
}
|
|
else if (prop.Flags == "proto")
|
|
{
|
|
sb.AppendLine(padding + "\tbuffer.put( buf" + GetUpperName(propName) + " );");
|
|
continue;
|
|
}
|
|
else if (prop.Flags == "const")
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (prop.Flags == "protomask")
|
|
{
|
|
propName = "MsgUtil.MakeMsg( " + propName + ", true )";
|
|
}
|
|
|
|
sb.AppendLine(padding + "\tbuffer.put" + readerTypeMap[typestr] + "( " + typecast + propName + " );");
|
|
}
|
|
|
|
sb.AppendLine();
|
|
|
|
sb.AppendLine();
|
|
sb.AppendLine(padding + "\tbuffer.flip();");
|
|
sb.AppendLine(padding + "\treturn buffer;");
|
|
sb.AppendLine(padding + "}");
|
|
}
|
|
|
|
private void EmitClassDeserializer(ClassNode cnode, StringBuilder sb, int level, int baseSize)
|
|
{
|
|
string padding = new String('\t', level);
|
|
|
|
sb.AppendLine();
|
|
sb.AppendLine(padding + "public void deserialize( ByteBuffer buffer ) throws InvalidProtocolBufferException");
|
|
sb.AppendLine(padding + "{");
|
|
|
|
if (cnode.Parent != null)
|
|
{
|
|
sb.AppendLine(padding + "\theader.deserialize( buffer );");
|
|
}
|
|
|
|
foreach (PropNode prop in cnode.childNodes)
|
|
{
|
|
string typestr = EmitType(prop.Type);
|
|
int size = CodeGenerator.GetTypeSize(prop);
|
|
|
|
string defflags = prop.Flags;
|
|
string symname = prop.Name;
|
|
|
|
if (defflags != null && defflags == "steamidmarshal")
|
|
{
|
|
}
|
|
else if (defflags != null && defflags == "const")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (size == 0)
|
|
{
|
|
if (prop.Flags != null && prop.Flags == "proto")
|
|
{
|
|
if (prop.FlagsOpt != null)
|
|
{
|
|
sb.AppendLine(padding + "\tbyte[] buf" + GetUpperName(prop.Name) + " = new byte[ " + prop.FlagsOpt + " ];");
|
|
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(padding + "\tbyte[] buf" + GetUpperName(prop.Name) + " = new byte[ buffer.limit() - buffer.position() ];");
|
|
}
|
|
|
|
sb.AppendLine(padding + "\tbuffer.get( buf" + GetUpperName(prop.Name) + " );");
|
|
sb.AppendLine(padding + "\t" + prop.Name + " = " + typestr + ".parseFrom( buf" + GetUpperName(prop.Name) + " );");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(padding + "\t" + prop.Name + ".deserialize( ms );");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string typecast = "";
|
|
string basetype = typestr;
|
|
|
|
if (!readerTypeMap.ContainsKey(typestr))
|
|
{
|
|
typecast = "(" + typestr + ")";
|
|
typestr = CodeGenerator.GetTypeOfSize(size, SupportsUnsignedTypes());
|
|
}
|
|
|
|
string call = "buffer.get" + readerTypeMap[typestr] + "()";
|
|
|
|
if (!String.IsNullOrEmpty(typecast))
|
|
{
|
|
call = basetype + ".lookup( " + call + " )";
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(prop.FlagsOpt))
|
|
{
|
|
call = "new " + typestr + "[" + prop.FlagsOpt + "]";
|
|
}
|
|
|
|
if (prop.Flags == "protomask")
|
|
{
|
|
call = "MsgUtil.GetMsg( " + call + " )";
|
|
}
|
|
|
|
if (!String.IsNullOrEmpty(prop.FlagsOpt))
|
|
{
|
|
// ctor creates array
|
|
sb.AppendLine(padding + "\tbuffer.get( " + symname + " );");
|
|
}
|
|
else
|
|
{
|
|
sb.AppendLine(padding + "\t" + symname + " = " + typecast + call + ";");
|
|
}
|
|
}
|
|
}
|
|
|
|
sb.AppendLine(padding + "}");
|
|
}
|
|
|
|
public bool SupportsUnsignedTypes()
|
|
{
|
|
return false;
|
|
}
|
|
|
|
public bool SupportsNamespace()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
}
|
|
}
|