2017-04-04 14:56:01 +02:00
using Newtonsoft.Json ;
2016-09-24 15:38:26 +02:00
using System ;
using System.Collections.Generic ;
using System.IO ;
using System.Linq ;
using System.Text ;
using System.Threading.Tasks ;
using System.CodeDom ;
using System.Reflection ;
using System.Text.RegularExpressions ;
2017-04-04 02:08:06 +02:00
using NDesk.Options ;
2016-09-24 15:38:26 +02:00
namespace TeleSharp.Generator
{
class Program
{
static List < String > keywords = new List < string > ( new string [ ] { "abstract" , "as" , "base" , "bool" , "break" , "byte" , "case" , "catch" , "char" , "checked" , "class" , "const" , "continue" , "decimal" , "default" , "delegate" , "do" , "double" , "else" , "enum" , "event" , "explicit" , "extern" , "false" , "finally" , "fixed" , "float" , "for" , "foreach" , "goto" , "if" , "implicit" , "in" , "in" , "int" , "interface" , "internal" , "is" , "lock" , "long" , "namespace" , "new" , "null" , "object" , "operator" , "out" , "out" , "override" , "params" , "private" , "protected" , "public" , "readonly" , "ref" , "return" , "sbyte" , "sealed" , "short" , "sizeof" , "stackalloc" , "static" , "string" , "struct" , "switch" , "this" , "throw" , "true" , "try" , "typeof" , "uint" , "ulong" , "unchecked" , "unsafe" , "ushort" , "using" , "virtual" , "void" , "volatile" , "while" , "add" , "alias" , "ascending" , "async" , "await" , "descending" , "dynamic" , "from" , "get" , "global" , "group" , "into" , "join" , "let" , "orderby" , "partial" , "partial" , "remove" , "select" , "set" , "value" , "var" , "where" , "where" , "yield" } ) ;
static List < String > interfacesList = new List < string > ( ) ;
static List < String > classesList = new List < string > ( ) ;
2017-04-04 02:08:06 +02:00
static void DisplayHelp ( bool full = true )
{
Console . WriteLine ( "TLSharp TL Parser v1.0, a TL schema to C# transcompiler" ) ;
Console . WriteLine ( "usage: TeleSharp.Generator [OPTIONS] INPUT [OUTPUT]" ) ;
Console . WriteLine ( ) ;
if ( full )
{
Console . WriteLine ( "Options:" ) ;
Console . WriteLine ( " -f, --format Sets input format." ) ;
Console . WriteLine ( " Accepted formats are \"tl\" and \"json\"." ) ;
Console . WriteLine ( " --template-abstract Sets the abstract class template" ) ;
Console . WriteLine ( " --template-class Sets the class template" ) ;
Console . WriteLine ( " --template-method Sets the method template" ) ;
Console . WriteLine ( " --target-namespace Sets the target namespace" ) ;
Console . WriteLine ( " Default is \"TeleSharp.TL\"" ) ;
Console . WriteLine ( " --output-json Only Parses TL and outputs schema as JSON" ) ;
Console . WriteLine ( " -h, --help Displays this help message" ) ;
Console . WriteLine ( ) ;
Console . WriteLine ( "For more information, please read the manual," ) ;
Console . WriteLine ( "or visit the GitHub page." ) ;
Console . WriteLine ( "Submit your bug reports to our GitHub repository." ) ;
}
else
{
Console . WriteLine ( "Try `TeleSharp.Generator --help' for more options." ) ;
}
}
enum Format
{
TL ,
JSON
}
2016-09-24 15:38:26 +02:00
static void Main ( string [ ] args )
{
2017-04-04 02:08:06 +02:00
string Json = "" ;
string inputPath = "" ;
string outputPath = "" ;
Format format = Format . TL ;
bool forceFormat = false ;
bool outputJson = false ;
bool showHelp = false ;
2016-09-24 15:38:26 +02:00
string AbsStyle = File . ReadAllText ( "ConstructorAbs.tmp" ) ;
string NormalStyle = File . ReadAllText ( "Constructor.tmp" ) ;
string MethodStyle = File . ReadAllText ( "Method.tmp" ) ;
2017-04-04 02:08:06 +02:00
string TargetNamespace = "TeleSharp.TL" ;
bool invalidFormat = false ;
bool invalidTargetNamespace = false ;
OptionSet optionset = new OptionSet ( )
. Add ( "h|help" , h = > showHelp = h ! = null )
. Add ( "f|format=" , f = >
{
f = f ? ? "" ;
if ( f ! = null )
forceFormat = true ;
switch ( f . ToLower ( ) )
{
case "tl" :
format = Format . TL ;
break ;
case "json" :
format = Format . JSON ;
break ;
case "" :
format = Format . TL ;
break ;
default :
invalidFormat = true ;
break ;
}
} )
. Add ( "target-namespace=" , a = >
{
if ( ! string . IsNullOrEmpty ( a ) )
{
Match m = Regex . Match ( a , @"(@?[a-z_A-Z]\w+(?:\.@?[a-z_A-Z]\w+)*)" ) ;
if ( m . Success )
{
TargetNamespace = m . Groups [ 0 ] . Value ;
}
}
else
{
invalidTargetNamespace = true ;
}
} )
. Add ( "output-json" , a = > outputJson = a ! = null )
. Add ( "template-abstract=" , a = > AbsStyle = ( a ! = null ) ? File . ReadAllText ( a ) : AbsStyle )
. Add ( "template-normal=" , a = > NormalStyle = ( a ! = null ) ? File . ReadAllText ( a ) : NormalStyle )
. Add ( "template-method=" , a = > MethodStyle = ( a ! = null ) ? File . ReadAllText ( a ) : MethodStyle ) ;
List < string > extra ;
try
{
extra = optionset . Parse ( args ) ;
}
catch ( OptionException e )
{
Console . Write ( "Error: " ) ;
Console . WriteLine ( e . Message ) ;
Console . WriteLine ( "Try `TeleSharp.Generator --help' for more information." ) ;
return ;
}
if ( showHelp )
{
DisplayHelp ( true ) ;
return ;
}
if ( extra = = null | | extra . Count = = 0 )
{
DisplayHelp ( false ) ;
return ;
}
if ( invalidFormat )
{
Console . WriteLine ( "Error: Invalid input format." ) ;
Console . WriteLine ( "Try `TeleSharp.Generator --help' for more information." ) ;
return ;
}
if ( invalidTargetNamespace )
{
Console . WriteLine ( "Error: Invalid target namespace." ) ;
Console . WriteLine ( "Try `TeleSharp.Generator --help' for more information." ) ;
return ;
}
2017-04-07 03:22:55 +02:00
2017-04-04 02:08:06 +02:00
inputPath = extra [ 0 ] ;
if ( ! forceFormat )
{
string ext = Path . GetExtension ( extra [ 0 ] ) ;
if ( ext = = "json" )
{
format = Format . JSON ;
}
}
if ( extra . Count > 1 )
{
outputPath = extra [ 1 ] ;
}
else
{ // no output path provided
if ( ! outputJson )
outputPath = Path . GetDirectoryName ( Path . GetFullPath ( extra [ 0 ] ) ) ;
else
outputPath = Path . ChangeExtension ( inputPath , ".json" ) ;
}
Console . WriteLine ( "TLSharp TL Parser v1.0, a TL schema to C# transcompiler" ) ;
Json = File . ReadAllText ( inputPath ) ;
if ( format = = Format . TL )
{ // if input is tl, convert to json
Json = TL2JSON . ParseToJson ( Json ) ;
Console . WriteLine ( "Converting TL to JSON..." ) ;
}
if ( outputJson )
{
File . WriteAllText ( outputPath , Json ) ;
return ;
}
#region Translate to C #
2016-09-24 15:38:26 +02:00
Schema schema = JsonConvert . DeserializeObject < Schema > ( Json ) ;
2017-04-07 03:22:55 +02:00
foreach ( var c in schema . Constructors )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
interfacesList . Add ( c . BaseType ) ;
classesList . Add ( c . ConstructorName ) ;
2016-09-24 15:38:26 +02:00
}
2017-04-04 02:08:06 +02:00
Console . WriteLine ( "Implementing abstract classes..." ) ;
2017-04-07 03:22:55 +02:00
var abstractParams = new Dictionary < string , List < Param > > ( ) ;
#region Abstract classes
foreach ( var c in schema . Constructors )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
var list = schema . Constructors . Where ( x = > x . BaseType = = c . BaseType ) ; // check if there is a dependence on base type of this class (base type is an abstract class)
2016-09-24 15:38:26 +02:00
if ( list . Count ( ) > 1 )
{
2017-04-07 03:22:55 +02:00
string path = Path . Combine ( outputPath , GetNameSpace ( c . BaseType , TargetNamespace ) . Replace ( TargetNamespace , @"TL\" ) . Replace ( "." , "" ) , GetNameofClass ( c . BaseType , true ) + ".cs" ) . Replace ( @"\\" , @"\" ) ;
2016-09-24 15:38:26 +02:00
FileStream classFile = MakeFile ( path ) ;
using ( StreamWriter writer = new StreamWriter ( classFile ) )
{
2017-04-07 03:22:55 +02:00
string temp = AbsStyle . Replace ( "/* NAMESPACE */" , GetNameSpace ( c . BaseType , TargetNamespace ) . TrimEnd ( '.' ) ) ;
temp = temp . Replace ( "/* NAME */" , GetNameofClass ( c . BaseType , true ) ) ;
2016-09-24 15:38:26 +02:00
writer . Write ( temp ) ;
writer . Close ( ) ;
classFile . Close ( ) ;
}
}
else
{
2017-04-07 03:22:55 +02:00
interfacesList . Remove ( list . First ( ) . BaseType ) ;
list . First ( ) . BaseType = "himself" ;
2016-09-24 15:38:26 +02:00
}
}
2017-04-07 03:22:55 +02:00
#endregion
2017-04-04 02:08:06 +02:00
Console . WriteLine ( "Implementing types..." ) ;
2017-04-07 03:22:55 +02:00
#region Constructors
foreach ( var c in schema . Constructors )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
string path = Path . Combine ( outputPath , GetNameSpace ( c . ConstructorName , TargetNamespace ) . Replace ( TargetNamespace , @"TL\" ) . Replace ( "." , "" ) , GetNameofClass ( c . ConstructorName , false ) + ".cs" ) . Replace ( @"\\" , @"\" ) ;
2016-09-24 15:38:26 +02:00
FileStream classFile = MakeFile ( path ) ;
using ( StreamWriter writer = new StreamWriter ( classFile ) )
{
#region About Class
2017-04-07 03:22:55 +02:00
string temp = NormalStyle . Replace ( "/* NAMESPACE */" , GetNameSpace ( c . ConstructorName , TargetNamespace ) . TrimEnd ( '.' ) ) ;
temp = ( c . BaseType = = "himself" ) ?
2017-04-04 14:56:01 +02:00
temp . Replace ( "/* PARENT */" , "TLObject" ) :
2017-04-07 03:22:55 +02:00
temp . Replace ( "/* PARENT */" , GetNameofClass ( c . BaseType , true ) ) ;
temp = temp . Replace ( "/*Constructor*/" , c . Id . ToString ( ) ) ;
temp = temp . Replace ( "/* NAME */" , GetNameofClass ( c . ConstructorName , false ) ) ;
2016-09-24 15:38:26 +02:00
#endregion
#region Fields
2017-04-04 02:08:06 +02:00
/ *
Note : Fields were mostly moved to abstract classes to provide maximum polymorphism usability .
* /
//string fields = "";
2017-04-07 03:22:55 +02:00
string parent_name = GetNameofClass ( c . BaseType , true ) ;
if ( c . BaseType ! = "himself" )
2016-09-24 15:38:26 +02:00
{
2017-04-04 02:08:06 +02:00
foreach ( var tmp in c . Params )
{
2017-04-07 03:22:55 +02:00
Param field = new Param { Name = tmp . Name , Type = tmp . Type } ;
if ( abstractParams . All ( item = > item . Key ! = c . BaseType ) )
abstractParams . Add ( c . BaseType , new List < Param > ( ) ) ;
else if ( ! abstractParams [ c . BaseType ] . Any ( f = > f . Name = = field . Name & & f . Type = = field . Type ) )
abstractParams [ c . BaseType ] . Add ( field ) ;
2017-04-04 02:08:06 +02:00
}
}
else
{
string fields = "" ;
2017-04-07 03:22:55 +02:00
foreach ( var param in c . Params )
2017-04-04 02:08:06 +02:00
{
2017-04-07 03:22:55 +02:00
fields + = $" public {CheckForFlagBase(param.Type, GetTypeName(param.Type))} {CheckForKeyword(param.Name)} " + "{ get; set; }" + Environment . NewLine ;
2017-04-04 02:08:06 +02:00
}
temp = temp . Replace ( "/* PARAMS */" , fields ) ;
2016-09-24 15:38:26 +02:00
}
#endregion
#region ComputeFlagFunc
2017-04-07 03:22:55 +02:00
if ( c . Params . All ( x = > x . Name ! = "flags" ) ) temp = temp . Replace ( "/* COMPUTE */" , "" ) ;
2016-09-24 15:38:26 +02:00
else
{
var compute = "flags = 0;" + Environment . NewLine ;
2017-04-07 03:22:55 +02:00
foreach ( var param in c . Params . Where ( x = > IsFlagBase ( x . Type ) ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
if ( IsTrueFlag ( param . Type ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
compute + = $"flags = {CheckForKeyword(param.Name)} ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
else
{
2017-04-07 03:22:55 +02:00
compute + = $"flags = {CheckForKeyword(param.Name)} != null ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
}
temp = temp . Replace ( "/* COMPUTE */" , compute ) ;
}
#endregion
#region SerializeFunc
var serialize = "" ;
2017-04-07 03:22:55 +02:00
if ( c . Params . Any ( x = > x . Name = = "flags" ) )
2017-04-04 14:56:01 +02:00
serialize + = "ComputeFlags();" + Environment . NewLine + "bw.Write(flags);" + Environment . NewLine ;
2017-04-07 03:22:55 +02:00
foreach ( var p in c . Params . Where ( x = > x . Name ! = "flags" ) )
2016-09-24 15:38:26 +02:00
{
serialize + = WriteWriteCode ( p ) + Environment . NewLine ;
}
temp = temp . Replace ( "/* SERIALIZE */" , serialize ) ;
#endregion
#region DeSerializeFunc
var deserialize = "" ;
foreach ( var p in c . Params )
{
deserialize + = WriteReadCode ( p ) + Environment . NewLine ;
}
temp = temp . Replace ( "/* DESERIALIZE */" , deserialize ) ;
#endregion
writer . Write ( temp ) ;
writer . Close ( ) ;
classFile . Close ( ) ;
}
}
2017-04-07 03:22:55 +02:00
#endregion
2017-04-04 02:08:06 +02:00
Console . WriteLine ( "Implementing methods..." ) ;
2017-04-07 03:22:55 +02:00
#region Methods
foreach ( var c in schema . Methods )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
string path = Path . Combine ( outputPath , GetNameSpace ( c . MethodName , TargetNamespace ) . Replace ( TargetNamespace , @"TL\" ) . Replace ( "." , "" ) , GetNameofClass ( c . MethodName , false , true ) + ".cs" ) . Replace ( @"\\" , @"\" ) ;
2016-09-24 15:38:26 +02:00
FileStream classFile = MakeFile ( path ) ;
using ( StreamWriter writer = new StreamWriter ( classFile ) )
{
#region About Class
2017-04-07 03:22:55 +02:00
string temp = MethodStyle . Replace ( "/* NAMESPACE */" , GetNameSpace ( c . MethodName , TargetNamespace ) . TrimEnd ( '.' ) ) ;
2016-09-24 15:38:26 +02:00
temp = temp . Replace ( "/* PARENT */" , "TLMethod" ) ;
2017-04-07 03:22:55 +02:00
temp = temp . Replace ( "/*Constructor*/" , c . Id . ToString ( ) ) ;
temp = temp . Replace ( "/* NAME */" , GetNameofClass ( c . MethodName , false , true ) ) ;
2016-09-24 15:38:26 +02:00
#endregion
#region Fields
string fields = "" ;
foreach ( var tmp in c . Params )
{
2017-04-07 03:22:55 +02:00
fields + = $" public {CheckForFlagBase(tmp.Type, GetTypeName(tmp.Type))} {CheckForKeyword(tmp.Name)} " + "{ get; set; }" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
2017-04-07 03:22:55 +02:00
fields + = $" public {CheckForFlagBase(c.ResponseType, GetTypeName(c.ResponseType))} Response" + "{ get; set; }" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
temp = temp . Replace ( "/* PARAMS */" , fields ) ;
#endregion
#region ComputeFlagFunc
2017-04-07 03:22:55 +02:00
if ( ! c . Params . Any ( x = > x . Name = = "flags" ) ) temp = temp . Replace ( "/* COMPUTE */" , "" ) ;
2016-09-24 15:38:26 +02:00
else
{
var compute = "flags = 0;" + Environment . NewLine ;
2017-04-07 03:22:55 +02:00
foreach ( var param in c . Params . Where ( x = > IsFlagBase ( x . Type ) ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
if ( IsTrueFlag ( param . Type ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
compute + = $"flags = {CheckForKeyword(param.Name)} ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
else
{
2017-04-07 03:22:55 +02:00
compute + = $"flags = {CheckForKeyword(param.Name)} != null ? (flags | {GetBitMask(param.Type)}) : (flags & ~{GetBitMask(param.Type)});" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
}
temp = temp . Replace ( "/* COMPUTE */" , compute ) ;
}
#endregion
#region SerializeFunc
var serialize = "" ;
2017-04-07 03:22:55 +02:00
if ( c . Params . Any ( x = > x . Name = = "flags" ) ) serialize + = "ComputeFlags();" + Environment . NewLine + "bw.Write(flags);" + Environment . NewLine ;
foreach ( var p in c . Params . Where ( x = > x . Name ! = "flags" ) )
2016-09-24 15:38:26 +02:00
{
serialize + = WriteWriteCode ( p ) + Environment . NewLine ;
}
temp = temp . Replace ( "/* SERIALIZE */" , serialize ) ;
#endregion
#region DeSerializeFunc
var deserialize = "" ;
foreach ( var p in c . Params )
{
deserialize + = WriteReadCode ( p ) + Environment . NewLine ;
}
temp = temp . Replace ( "/* DESERIALIZE */" , deserialize ) ;
#endregion
#region DeSerializeRespFunc
var deserializeResp = "" ;
2017-04-07 03:22:55 +02:00
Param p2 = new Param ( ) { Name = "Response" , Type = c . ResponseType } ;
2016-09-24 15:38:26 +02:00
deserializeResp + = WriteReadCode ( p2 ) + Environment . NewLine ;
temp = temp . Replace ( "/* DESERIALIZEResp */" , deserializeResp ) ;
#endregion
writer . Write ( temp ) ;
writer . Close ( ) ;
classFile . Close ( ) ;
}
}
2017-04-07 03:22:55 +02:00
#endregion
2017-04-04 02:08:06 +02:00
Console . WriteLine ( "Adding fields to abstract classes..." ) ;
// add fields to abstract classes
2017-04-07 03:22:55 +02:00
foreach ( KeyValuePair < string , List < Param > > absClass in abstractParams )
2017-04-04 02:08:06 +02:00
{
string path = Path . Combine ( outputPath , GetNameSpace ( absClass . Key , TargetNamespace ) . Replace ( TargetNamespace , @"TL\" ) . Replace ( "." , "" ) , GetNameofClass ( absClass . Key , true ) + ".cs" ) . Replace ( @"\\" , @"\" ) ;
string tmp = File . ReadAllText ( path ) ;
tmp = tmp . Replace ( "/* PARAMS */" , ConvertPropertyList ( absClass . Value ) ) ;
File . WriteAllText ( path , tmp ) ;
}
#endregion
2017-04-07 03:22:55 +02:00
2017-04-04 02:08:06 +02:00
Console . WriteLine ( "Done." ) ;
}
2017-04-07 03:22:55 +02:00
public static string ConvertPropertyList ( List < Param > list )
2017-04-04 02:08:06 +02:00
{
string output = "" ;
2017-04-07 03:22:55 +02:00
foreach ( var param in list )
2017-04-04 02:08:06 +02:00
{
2017-04-07 03:22:55 +02:00
output + = $" public {CheckForFlagBase(param.Type, GetTypeName(param.Type))} {CheckForKeyword(param.Name)} " + "{ get; set; }" + Environment . NewLine ;
2017-04-04 02:08:06 +02:00
}
return output ;
2016-09-24 15:38:26 +02:00
}
2017-04-04 02:08:06 +02:00
2016-09-24 15:38:26 +02:00
public static string FormatName ( string input )
{
if ( String . IsNullOrEmpty ( input ) )
2017-04-04 02:08:06 +02:00
throw new ArgumentException ( "ARGH! Class Name was empty." ) ;
2016-09-24 15:38:26 +02:00
if ( input . IndexOf ( '.' ) ! = - 1 )
{
input = input . Replace ( "." , " " ) ;
var temp = "" ;
foreach ( var s in input . Split ( ' ' ) )
{
temp + = FormatName ( s ) + " " ;
}
input = temp . Trim ( ) ;
}
return input . First ( ) . ToString ( ) . ToUpper ( ) + input . Substring ( 1 ) ;
}
public static string CheckForKeyword ( string name )
{
if ( keywords . Contains ( name ) ) return "@" + name ;
return name ;
}
public static string GetNameofClass ( string type , bool isinterface = false , bool ismethod = false )
{
if ( ! ismethod )
{
if ( type . IndexOf ( '.' ) ! = - 1 & & type . IndexOf ( '?' ) = = - 1 )
return isinterface ? "TLAbs" + FormatName ( type . Split ( '.' ) [ 1 ] ) : "TL" + FormatName ( type . Split ( '.' ) [ 1 ] ) ;
else if ( type . IndexOf ( '.' ) ! = - 1 & & type . IndexOf ( '?' ) ! = - 1 )
return isinterface ? "TLAbs" + FormatName ( type . Split ( '?' ) [ 1 ] ) : "TL" + FormatName ( type . Split ( '?' ) [ 1 ] ) ;
else
return isinterface ? "TLAbs" + FormatName ( type ) : "TL" + FormatName ( type ) ;
}
else
{
if ( type . IndexOf ( '.' ) ! = - 1 & & type . IndexOf ( '?' ) = = - 1 )
return "TLRequest" + FormatName ( type . Split ( '.' ) [ 1 ] ) ;
else if ( type . IndexOf ( '.' ) ! = - 1 & & type . IndexOf ( '?' ) ! = - 1 )
return "TLRequest" + FormatName ( type . Split ( '?' ) [ 1 ] ) ;
else
2016-10-15 12:35:54 +02:00
return "TLRequest" + FormatName ( type ) ;
2016-09-24 15:38:26 +02:00
}
}
private static bool IsFlagBase ( string type )
{
return type . IndexOf ( "?" ) ! = - 1 ;
}
private static int GetBitMask ( string type )
{
return ( int ) Math . Pow ( ( double ) 2 , ( double ) int . Parse ( type . Split ( '?' ) [ 0 ] . Split ( '.' ) [ 1 ] ) ) ;
}
private static bool IsTrueFlag ( string type )
{
return type . Split ( '?' ) [ 1 ] = = "true" ;
}
2017-04-04 02:08:06 +02:00
public static string GetNameSpace ( string type , string targetns )
2016-09-24 15:38:26 +02:00
{
if ( type . IndexOf ( '.' ) ! = - 1 )
2017-04-07 03:47:42 +02:00
return targetns + "." + FormatName ( type . Split ( '.' ) [ 0 ] ) ;
2016-09-24 15:38:26 +02:00
else
2017-04-04 02:08:06 +02:00
return targetns ;
2016-09-24 15:38:26 +02:00
}
public static string CheckForFlagBase ( string type , string result )
{
if ( type . IndexOf ( '?' ) = = - 1 )
return result ;
2017-04-07 03:22:55 +02:00
string innerType = type . Split ( '?' ) [ 1 ] ;
if ( innerType = = "true" )
return result ;
if ( ( new string [ ] { "bool" , "int" , "uint" , "long" , "BigMath.Int128" , "BigMath.Int256" , "double" } ) . Contains ( result ) )
return result + "?" ;
return result ;
2016-09-24 15:38:26 +02:00
}
public static string GetTypeName ( string type )
{
switch ( type . ToLower ( ) )
{
case "#" :
case "int" :
return "int" ;
2017-04-07 03:22:55 +02:00
case "int128" :
return "BigMath.Int128" ;
case "int256" :
return "BigMath.Int256" ;
2016-09-24 15:38:26 +02:00
case "uint" :
return "uint" ;
case "long" :
return "long" ;
case "double" :
return "double" ;
case "string" :
return "string" ;
case "bytes" :
return "byte[]" ;
case "true" :
case "bool" :
return "bool" ;
case "!x" :
return "TLObject" ;
case "x" :
return "TLObject" ;
2017-04-04 02:08:06 +02:00
case "vector t" :
return "List<T>" ;
2016-09-24 15:38:26 +02:00
}
2016-10-15 12:35:54 +02:00
2017-04-04 02:08:06 +02:00
if ( type . StartsWith ( "Vector<" ) )
2016-09-24 15:38:26 +02:00
return "TLVector<" + GetTypeName ( type . Replace ( "Vector<" , "" ) . Replace ( ">" , "" ) ) + ">" ;
2016-10-15 12:35:54 +02:00
if ( type . ToLower ( ) . Contains ( "inputcontact" ) )
return "TLInputPhoneContact" ;
2017-04-04 02:08:06 +02:00
2016-10-15 12:35:54 +02:00
if ( type . IndexOf ( '.' ) ! = - 1 & & type . IndexOf ( '?' ) = = - 1 )
2016-09-24 15:38:26 +02:00
{
2016-10-15 12:35:54 +02:00
if ( interfacesList . Any ( x = > x . ToLower ( ) = = ( type ) . ToLower ( ) ) )
return FormatName ( type . Split ( '.' ) [ 0 ] ) + "." + "TLAbs" + type . Split ( '.' ) [ 1 ] ;
else if ( classesList . Any ( x = > x . ToLower ( ) = = ( type ) . ToLower ( ) ) )
return FormatName ( type . Split ( '.' ) [ 0 ] ) + "." + "TL" + type . Split ( '.' ) [ 1 ] ;
2016-09-24 15:38:26 +02:00
else
2016-10-15 12:35:54 +02:00
return FormatName ( type . Split ( '.' ) [ 1 ] ) ;
}
else if ( type . IndexOf ( '?' ) = = - 1 )
{
if ( interfacesList . Any ( x = > x . ToLower ( ) = = type . ToLower ( ) ) )
return "TLAbs" + type ;
else if ( classesList . Any ( x = > x . ToLower ( ) = = type . ToLower ( ) ) )
return "TL" + type ;
else
return type ;
}
else
{
return GetTypeName ( type . Split ( '?' ) [ 1 ] ) ;
2016-09-24 15:38:26 +02:00
}
2016-10-15 12:35:54 +02:00
2016-09-24 15:38:26 +02:00
}
public static string LookTypeInLists ( string src )
{
if ( interfacesList . Any ( x = > x . ToLower ( ) = = src . ToLower ( ) ) )
return "TLAbs" + FormatName ( src ) ;
else if ( classesList . Any ( x = > x . ToLower ( ) = = src . ToLower ( ) ) )
return "TL" + FormatName ( src ) ;
else
return src ;
}
public static string WriteWriteCode ( Param p , bool flag = false )
{
2017-04-07 03:22:55 +02:00
switch ( p . Type . ToLower ( ) )
2016-09-24 15:38:26 +02:00
{
case "#" :
case "int" :
2017-04-07 03:22:55 +02:00
return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});" ;
2016-09-24 15:38:26 +02:00
case "long" :
2017-04-07 03:22:55 +02:00
return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});" ;
2016-09-24 15:38:26 +02:00
case "string" :
2017-04-07 03:22:55 +02:00
return $"StringUtil.Serialize({CheckForKeyword(p.Name)},bw);" ;
2016-09-24 15:38:26 +02:00
case "bool" :
2017-04-07 03:22:55 +02:00
return flag ? $"BoolUtil.Serialize({CheckForKeyword(p.Name)}.Value,bw);" : $"BoolUtil.Serialize({CheckForKeyword(p.Name)},bw);" ;
2016-09-24 15:38:26 +02:00
case "true" :
2017-04-07 03:22:55 +02:00
return $"BoolUtil.Serialize({CheckForKeyword(p.Name)},bw);" ;
2016-09-24 15:38:26 +02:00
case "bytes" :
2017-04-07 03:22:55 +02:00
return $"BytesUtil.Serialize({CheckForKeyword(p.Name)},bw);" ;
2016-09-24 15:38:26 +02:00
case "double" :
2017-04-07 03:22:55 +02:00
return flag ? $"bw.Write({CheckForKeyword(p.Name)}.Value);" : $"bw.Write({CheckForKeyword(p.Name)});" ;
2016-09-24 15:38:26 +02:00
default :
2017-04-07 03:22:55 +02:00
if ( ! IsFlagBase ( p . Type ) )
return $"ObjectUtils.SerializeObject({CheckForKeyword(p.Name)},bw);" ;
2016-09-24 15:38:26 +02:00
else
{
2017-04-07 03:22:55 +02:00
if ( IsTrueFlag ( p . Type ) )
2016-09-24 15:38:26 +02:00
return $"" ;
else
{
2017-04-07 03:22:55 +02:00
Param p2 = new Param ( ) { Name = p . Name , Type = p . Type . Split ( '?' ) [ 1 ] } ;
return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment . NewLine +
2016-09-24 15:38:26 +02:00
WriteWriteCode ( p2 , true ) ;
}
}
}
}
public static string WriteReadCode ( Param p )
{
2017-04-07 03:22:55 +02:00
switch ( p . Type . ToLower ( ) )
2016-09-24 15:38:26 +02:00
{
case "#" :
case "int" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = br.ReadInt32();" ;
2016-09-24 15:38:26 +02:00
case "long" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = br.ReadInt64();" ;
2016-09-24 15:38:26 +02:00
case "string" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = StringUtil.Deserialize(br);" ;
2016-09-24 15:38:26 +02:00
case "bool" :
case "true" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = BoolUtil.Deserialize(br);" ;
2016-09-24 15:38:26 +02:00
case "bytes" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = BytesUtil.Deserialize(br);" ;
2016-09-24 15:38:26 +02:00
case "double" :
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = br.ReadDouble();" ;
2016-09-24 15:38:26 +02:00
default :
2017-04-07 03:22:55 +02:00
if ( ! IsFlagBase ( p . Type ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
if ( p . Type . ToLower ( ) . Contains ( "vector" ) )
2016-09-24 15:38:26 +02:00
{
2017-04-07 03:22:55 +02:00
return $"{CheckForKeyword(p.Name)} = ({GetTypeName(p.Type)})ObjectUtils.DeserializeVector<{GetTypeName(p.Type).Replace(" TLVector < ", " ").Replace(" > ", " ")}>(br);" ;
2016-09-24 15:38:26 +02:00
}
2017-04-07 03:22:55 +02:00
else return $"{CheckForKeyword(p.Name)} = ({GetTypeName(p.Type)})ObjectUtils.DeserializeObject(br);" ;
2016-09-24 15:38:26 +02:00
}
else
{
2017-04-07 03:22:55 +02:00
if ( IsTrueFlag ( p . Type ) )
return $"{CheckForKeyword(p.Name)} = (flags & {GetBitMask(p.Type).ToString()}) != 0;" ;
2016-09-24 15:38:26 +02:00
else
{
2017-04-07 03:22:55 +02:00
Param p2 = new Param ( ) { Name = p . Name , Type = p . Type . Split ( '?' ) [ 1 ] } ;
return $"if ((flags & {GetBitMask(p.Type).ToString()}) != 0)" + Environment . NewLine +
2016-09-24 15:38:26 +02:00
WriteReadCode ( p2 ) + Environment . NewLine +
"else" + Environment . NewLine +
2017-04-07 03:22:55 +02:00
$"{CheckForKeyword(p.Name)} = null;" + Environment . NewLine ;
2016-09-24 15:38:26 +02:00
}
}
}
}
public static FileStream MakeFile ( string path )
{
if ( ! Directory . Exists ( Path . GetDirectoryName ( path ) ) )
Directory . CreateDirectory ( Path . GetDirectoryName ( path ) ) ;
if ( File . Exists ( path ) )
File . Delete ( path ) ;
return File . OpenWrite ( path ) ;
}
}
2017-04-04 02:08:06 +02:00
struct Property
{
2017-04-04 14:56:01 +02:00
public Property ( string type , string name ) {
Type = type ;
Name = name ;
}
public string Type ;
public string Name ;
2017-04-04 02:08:06 +02:00
public override bool Equals ( object obj )
{
if ( obj . GetType ( ) = = typeof ( Property ) )
{
2017-04-04 14:56:01 +02:00
return ( ( Property ) obj ) . Type = = Type & & ( ( Property ) obj ) . Name = = Name ;
2017-04-04 02:08:06 +02:00
}
return false ;
}
}
2017-04-04 14:56:01 +02:00
}