2021-08-04 00:40:09 +02:00
|
|
|
|
using System;
|
2021-09-26 05:07:17 +02:00
|
|
|
|
using System.Collections.Generic;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.IO.Compression;
|
|
|
|
|
|
using System.Linq;
|
|
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
using System.Security.Cryptography;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
|
2023-07-08 01:34:31 +02:00
|
|
|
|
#pragma warning disable IDE1006 // Naming Styles
|
|
|
|
|
|
|
2021-08-04 00:40:09 +02:00
|
|
|
|
namespace TL
|
|
|
|
|
|
{
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#if MTPG
|
|
|
|
|
|
public interface IObject { void WriteTL(BinaryWriter writer); }
|
|
|
|
|
|
#else
|
2021-11-07 16:52:58 +01:00
|
|
|
|
public interface IObject { }
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#endif
|
2021-11-07 16:52:58 +01:00
|
|
|
|
public interface IMethod<ReturnType> : IObject { }
|
2021-11-09 23:23:16 +01:00
|
|
|
|
public interface IPeerResolver { IPeerInfo UserOrChat(Peer peer); }
|
2021-08-04 00:40:09 +02:00
|
|
|
|
|
2022-02-19 03:30:50 +01:00
|
|
|
|
[AttributeUsage(AttributeTargets.Class)]
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed class TLDefAttribute(uint ctorNb) : Attribute
|
2022-02-19 03:30:50 +01:00
|
|
|
|
{
|
2024-03-12 19:07:48 +01:00
|
|
|
|
public readonly uint CtorNb = ctorNb;
|
2022-02-19 03:30:50 +01:00
|
|
|
|
public bool inheritBefore;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[AttributeUsage(AttributeTargets.Field)]
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed class IfFlagAttribute(int bit) : Attribute
|
2022-02-19 03:30:50 +01:00
|
|
|
|
{
|
2024-03-12 19:07:48 +01:00
|
|
|
|
public readonly int Bit = bit;
|
2022-02-19 03:30:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-04 11:12:59 +02:00
|
|
|
|
public sealed class RpcException(int code, string message, int x = -1) : WTelegram.WTException(message)
|
2022-02-19 03:30:50 +01:00
|
|
|
|
{
|
2024-04-04 11:12:59 +02:00
|
|
|
|
public readonly int Code = code;
|
2022-04-11 12:08:17 +02:00
|
|
|
|
/// <summary>The value of X in the message, -1 if no variable X was found</summary>
|
2024-03-12 19:07:48 +01:00
|
|
|
|
public readonly int X = x;
|
2022-02-19 03:30:50 +01:00
|
|
|
|
public override string ToString() { var str = base.ToString(); return str.Insert(str.IndexOf(':') + 1, " " + Code); }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class ReactorError : IObject
|
2022-02-19 03:30:50 +01:00
|
|
|
|
{
|
|
|
|
|
|
public Exception Exception;
|
2024-03-28 12:13:56 +01:00
|
|
|
|
public void WriteTL(BinaryWriter writer) => throw new NotSupportedException();
|
2022-02-19 03:30:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-21 16:31:57 +02:00
|
|
|
|
public static class Serialization
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2023-04-21 16:31:57 +02:00
|
|
|
|
public static void WriteTLObject<T>(this BinaryWriter writer, T obj) where T : IObject
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-09-30 03:40:08 +02:00
|
|
|
|
if (obj == null) { writer.WriteTLNull(typeof(T)); return; }
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#if MTPG
|
|
|
|
|
|
obj.WriteTL(writer);
|
|
|
|
|
|
#else
|
2021-08-09 11:41:50 +02:00
|
|
|
|
var type = obj.GetType();
|
2021-09-26 05:07:17 +02:00
|
|
|
|
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
|
|
|
|
|
var ctorNb = tlDef.CtorNb;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
writer.Write(ctorNb);
|
2022-10-01 13:56:43 +02:00
|
|
|
|
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
2021-11-09 15:01:59 +01:00
|
|
|
|
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
2022-11-01 19:26:40 +01:00
|
|
|
|
ulong flags = 0;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
IfFlagAttribute ifFlag;
|
|
|
|
|
|
foreach (var field in fields)
|
|
|
|
|
|
{
|
2022-11-01 19:26:40 +01:00
|
|
|
|
if (((ifFlag = field.GetCustomAttribute<IfFlagAttribute>()) != null) && (flags & (1UL << ifFlag.Bit)) == 0) continue;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
object value = field.GetValue(obj);
|
2021-09-30 03:40:08 +02:00
|
|
|
|
writer.WriteTLValue(value, field.FieldType);
|
2022-11-01 19:26:40 +01:00
|
|
|
|
if (field.FieldType.IsEnum)
|
|
|
|
|
|
if (field.Name == "flags") flags = (uint)value;
|
|
|
|
|
|
else if (field.Name == "flags2") flags |= (ulong)(uint)value << 32;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#endif
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-21 16:31:57 +02:00
|
|
|
|
public static IObject ReadTLObject(this BinaryReader reader, uint ctorNb = 0)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2024-04-22 17:28:44 +02:00
|
|
|
|
if (ctorNb == 0) ctorNb = reader.ReadUInt32();
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#if MTPG
|
2024-04-22 17:28:44 +02:00
|
|
|
|
if (!Layer.Table.TryGetValue(ctorNb, out var ctor))
|
|
|
|
|
|
throw new WTelegram.WTException($"Cannot find type for ctor #{ctorNb:x}");
|
|
|
|
|
|
return ctor?.Invoke(reader);
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#else
|
2024-04-16 15:19:12 +02:00
|
|
|
|
if (ctorNb == Layer.GZipedCtor) return (IObject)reader.ReadTLGzipped(typeof(IObject));
|
2021-09-17 04:53:02 +02:00
|
|
|
|
if (!Layer.Table.TryGetValue(ctorNb, out var type))
|
2023-04-02 13:44:23 +02:00
|
|
|
|
throw new WTelegram.WTException($"Cannot find type for ctor #{ctorNb:x}");
|
2021-09-30 03:40:08 +02:00
|
|
|
|
if (type == null) return null; // nullable ctor (class meaning is associated with null)
|
2021-09-26 05:07:17 +02:00
|
|
|
|
var tlDef = type.GetCustomAttribute<TLDefAttribute>();
|
2022-03-27 22:26:57 +02:00
|
|
|
|
var obj = Activator.CreateInstance(type, true);
|
2022-10-01 13:56:43 +02:00
|
|
|
|
IEnumerable<FieldInfo> fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public);
|
2021-11-09 15:01:59 +01:00
|
|
|
|
if (tlDef.inheritBefore) fields = fields.GroupBy(f => f.DeclaringType).Reverse().SelectMany(g => g);
|
2022-11-01 19:26:40 +01:00
|
|
|
|
ulong flags = 0;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
IfFlagAttribute ifFlag;
|
|
|
|
|
|
foreach (var field in fields)
|
|
|
|
|
|
{
|
2022-11-01 19:26:40 +01:00
|
|
|
|
if (((ifFlag = field.GetCustomAttribute<IfFlagAttribute>()) != null) && (flags & (1UL << ifFlag.Bit)) == 0) continue;
|
2021-08-09 11:41:50 +02:00
|
|
|
|
object value = reader.ReadTLValue(field.FieldType);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
field.SetValue(obj, value);
|
2022-11-01 19:26:40 +01:00
|
|
|
|
if (field.FieldType.IsEnum)
|
|
|
|
|
|
if (field.Name == "flags") flags = (uint)value;
|
|
|
|
|
|
else if (field.Name == "flags2") flags |= (ulong)(uint)value << 32;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
2022-01-17 15:06:29 +01:00
|
|
|
|
return (IObject)obj;
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#endif
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-09-30 03:40:08 +02:00
|
|
|
|
internal static void WriteTLValue(this BinaryWriter writer, object value, Type valueType)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-09-30 03:40:08 +02:00
|
|
|
|
if (value == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.WriteTLNull(valueType);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2021-08-04 00:40:09 +02:00
|
|
|
|
var type = value.GetType();
|
|
|
|
|
|
switch (Type.GetTypeCode(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
case TypeCode.Int32: writer.Write((int)value); break;
|
|
|
|
|
|
case TypeCode.Int64: writer.Write((long)value); break;
|
2022-02-19 03:30:50 +01:00
|
|
|
|
case TypeCode.UInt32: writer.Write((uint)value); break;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
case TypeCode.UInt64: writer.Write((ulong)value); break;
|
|
|
|
|
|
case TypeCode.Double: writer.Write((double)value); break;
|
2021-08-09 11:41:50 +02:00
|
|
|
|
case TypeCode.String: writer.WriteTLString((string)value); break;
|
|
|
|
|
|
case TypeCode.Boolean: writer.Write((bool)value ? 0x997275B5 : 0xBC799737); break;
|
2022-02-19 03:30:50 +01:00
|
|
|
|
case TypeCode.DateTime: writer.WriteTLStamp((DateTime)value); break;
|
2021-08-04 00:40:09 +02:00
|
|
|
|
case TypeCode.Object:
|
|
|
|
|
|
if (type.IsArray)
|
|
|
|
|
|
if (value is byte[] bytes)
|
2021-08-09 11:41:50 +02:00
|
|
|
|
writer.WriteTLBytes(bytes);
|
2021-11-07 16:50:59 +01:00
|
|
|
|
else if (value is _Message[] messages)
|
|
|
|
|
|
writer.WriteTLMessages(messages);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
else
|
2021-08-09 11:41:50 +02:00
|
|
|
|
writer.WriteTLVector((Array)value);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
else if (value is Int128 int128)
|
|
|
|
|
|
writer.Write(int128);
|
|
|
|
|
|
else if (value is Int256 int256)
|
|
|
|
|
|
writer.Write(int256);
|
2021-11-07 16:52:58 +01:00
|
|
|
|
else if (value is IObject tlObject)
|
2021-08-09 11:41:50 +02:00
|
|
|
|
WriteTLObject(writer, tlObject);
|
2022-02-04 02:51:14 +01:00
|
|
|
|
else if (type.IsEnum) // needed for Mono (enums in generic types are seen as TypeCode.Object)
|
|
|
|
|
|
writer.Write((uint)value);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
else
|
|
|
|
|
|
ShouldntBeHere();
|
|
|
|
|
|
break;
|
|
|
|
|
|
default:
|
|
|
|
|
|
ShouldntBeHere();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
internal static object ReadTLValue(this BinaryReader reader, Type type)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
|
|
|
|
|
switch (Type.GetTypeCode(type))
|
|
|
|
|
|
{
|
|
|
|
|
|
case TypeCode.Int32: return reader.ReadInt32();
|
|
|
|
|
|
case TypeCode.Int64: return reader.ReadInt64();
|
2022-02-19 03:30:50 +01:00
|
|
|
|
case TypeCode.UInt32: return reader.ReadUInt32();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
case TypeCode.UInt64: return reader.ReadUInt64();
|
|
|
|
|
|
case TypeCode.Double: return reader.ReadDouble();
|
2021-08-09 11:41:50 +02:00
|
|
|
|
case TypeCode.String: return reader.ReadTLString();
|
|
|
|
|
|
case TypeCode.DateTime: return reader.ReadTLStamp();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
case TypeCode.Boolean:
|
|
|
|
|
|
return reader.ReadUInt32() switch
|
|
|
|
|
|
{
|
|
|
|
|
|
0x997275b5 => true,
|
|
|
|
|
|
0xbc799737 => false,
|
2021-12-07 16:35:23 +01:00
|
|
|
|
Layer.RpcErrorCtor => reader.ReadTLObject(Layer.RpcErrorCtor),
|
2023-04-02 13:44:23 +02:00
|
|
|
|
var value => throw new WTelegram.WTException($"Invalid boolean value #{value:x}")
|
2021-08-04 00:40:09 +02:00
|
|
|
|
};
|
|
|
|
|
|
case TypeCode.Object:
|
|
|
|
|
|
if (type.IsArray)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (type == typeof(byte[]))
|
2021-08-09 11:41:50 +02:00
|
|
|
|
return reader.ReadTLBytes();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
else
|
2021-08-09 11:41:50 +02:00
|
|
|
|
return reader.ReadTLVector(type);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
else if (type == typeof(Int128))
|
|
|
|
|
|
return new Int128(reader);
|
|
|
|
|
|
else if (type == typeof(Int256))
|
|
|
|
|
|
return new Int256(reader);
|
2021-12-25 03:20:22 +01:00
|
|
|
|
else if (type == typeof(Dictionary<long, User>))
|
2023-04-09 14:14:56 +02:00
|
|
|
|
return reader.ReadTLDictionary<User>();
|
2021-10-20 19:12:50 +02:00
|
|
|
|
else if (type == typeof(Dictionary<long, ChatBase>))
|
2023-04-09 14:14:56 +02:00
|
|
|
|
return reader.ReadTLDictionary<ChatBase>();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
else
|
2021-08-13 07:06:44 +02:00
|
|
|
|
return reader.ReadTLObject();
|
2021-08-04 00:40:09 +02:00
|
|
|
|
default:
|
|
|
|
|
|
ShouldntBeHere();
|
|
|
|
|
|
return null;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-11-07 16:50:59 +01:00
|
|
|
|
internal static void WriteTLMessages(this BinaryWriter writer, _Message[] messages)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.Write(messages.Length);
|
|
|
|
|
|
foreach (var msg in messages)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.Write(msg.msg_id);
|
2024-02-25 03:09:49 +01:00
|
|
|
|
writer.Write(msg.seq_no);
|
2021-11-07 16:50:59 +01:00
|
|
|
|
var patchPos = writer.BaseStream.Position;
|
2023-07-06 10:17:29 +02:00
|
|
|
|
writer.Write(0); // patched below
|
2024-02-25 03:09:49 +01:00
|
|
|
|
if ((msg.seq_no & 1) != 0)
|
2021-11-21 00:43:39 +01:00
|
|
|
|
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38} #{(short)msg.msg_id.GetHashCode():X4}");
|
2021-11-07 16:50:59 +01:00
|
|
|
|
else
|
2021-11-21 00:43:39 +01:00
|
|
|
|
WTelegram.Helpers.Log(1, $" → {msg.body.GetType().Name.TrimEnd('_'),-38}");
|
2023-07-06 10:17:29 +02:00
|
|
|
|
writer.WriteTLObject(msg.body);
|
2021-11-07 16:50:59 +01:00
|
|
|
|
writer.BaseStream.Position = patchPos;
|
|
|
|
|
|
writer.Write((int)(writer.BaseStream.Length - patchPos - 4)); // patch bytes field
|
|
|
|
|
|
writer.Seek(0, SeekOrigin.End);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-28 12:13:56 +01:00
|
|
|
|
internal static void WriteTLVector(this BinaryWriter writer, Array array)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.Write(Layer.VectorCtor);
|
|
|
|
|
|
if (array == null) { writer.Write(0); return; }
|
|
|
|
|
|
int count = array.Length;
|
|
|
|
|
|
writer.Write(count);
|
|
|
|
|
|
var elementType = array.GetType().GetElementType();
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
writer.WriteTLValue(array.GetValue(i), elementType);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static T[] ReadTLRawVector<T>(this BinaryReader reader, uint ctorNb)
|
|
|
|
|
|
{
|
|
|
|
|
|
int count = reader.ReadInt32();
|
|
|
|
|
|
var array = new T[count];
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
array[i] = (T)reader.ReadTLObject(ctorNb);
|
|
|
|
|
|
return array;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static T[] ReadTLVector<T>(this BinaryReader reader)
|
|
|
|
|
|
{
|
|
|
|
|
|
var elementType = typeof(T);
|
|
|
|
|
|
if (reader.ReadUInt32() is not Layer.VectorCtor and uint ctorNb)
|
|
|
|
|
|
throw new WTelegram.WTException($"Cannot deserialize {elementType.Name}[] with ctor #{ctorNb:x}");
|
|
|
|
|
|
int count = reader.ReadInt32();
|
|
|
|
|
|
var array = new T[count];
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
array[i] = (T)reader.ReadTLValue(elementType);
|
|
|
|
|
|
return array;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
internal static Array ReadTLVector(this BinaryReader reader, Type type)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
|
|
|
|
|
var elementType = type.GetElementType();
|
2021-09-24 12:29:04 +02:00
|
|
|
|
uint ctorNb = reader.ReadUInt32();
|
|
|
|
|
|
if (ctorNb == Layer.VectorCtor)
|
|
|
|
|
|
{
|
|
|
|
|
|
int count = reader.ReadInt32();
|
|
|
|
|
|
Array array = (Array)Activator.CreateInstance(type, count);
|
2022-02-07 22:06:10 +01:00
|
|
|
|
if (elementType.IsEnum)
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
array.SetValue(Enum.ToObject(elementType, reader.ReadTLValue(elementType)), i);
|
|
|
|
|
|
else
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
array.SetValue(reader.ReadTLValue(elementType), i);
|
2021-09-24 12:29:04 +02:00
|
|
|
|
return array;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (ctorNb < 1024 && !elementType.IsAbstract && elementType.GetCustomAttribute<TLDefAttribute>() is TLDefAttribute attr)
|
|
|
|
|
|
{
|
|
|
|
|
|
int count = (int)ctorNb;
|
|
|
|
|
|
Array array = (Array)Activator.CreateInstance(type, count);
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
array.SetValue(reader.ReadTLObject(attr.CtorNb), i);
|
|
|
|
|
|
return array;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
2023-04-02 13:44:23 +02:00
|
|
|
|
throw new WTelegram.WTException($"Cannot deserialize {type.Name} with ctor #{ctorNb:x}");
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2023-04-09 14:14:56 +02:00
|
|
|
|
internal static Dictionary<long, T> ReadTLDictionary<T>(this BinaryReader reader) where T : class, IPeerInfo
|
2021-10-20 19:12:50 +02:00
|
|
|
|
{
|
|
|
|
|
|
uint ctorNb = reader.ReadUInt32();
|
|
|
|
|
|
if (ctorNb != Layer.VectorCtor)
|
2024-03-28 12:13:56 +01:00
|
|
|
|
throw new WTelegram.WTException($"Cannot deserialize Vector<{typeof(T).Name}> with ctor #{ctorNb:x}");
|
2021-10-20 19:12:50 +02:00
|
|
|
|
int count = reader.ReadInt32();
|
|
|
|
|
|
var dict = new Dictionary<long, T>(count);
|
|
|
|
|
|
for (int i = 0; i < count; i++)
|
|
|
|
|
|
{
|
2024-04-04 11:12:59 +02:00
|
|
|
|
var obj = reader.ReadTLObject();
|
|
|
|
|
|
if (obj is T value) dict[value.ID] = value;
|
|
|
|
|
|
else if (obj is UserEmpty ue) dict[ue.id] = null;
|
|
|
|
|
|
else throw new InvalidCastException($"ReadTLDictionary got '{obj?.GetType().Name}' instead of '{typeof(T).Name}'");
|
2021-10-20 19:12:50 +02:00
|
|
|
|
}
|
|
|
|
|
|
return dict;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
internal static void WriteTLStamp(this BinaryWriter writer, DateTime datetime)
|
2021-10-17 03:18:36 +02:00
|
|
|
|
=> writer.Write(datetime == DateTime.MaxValue ? int.MaxValue : (int)(datetime.ToUniversalTime().Ticks / 10000000 - 62135596800L));
|
2021-08-09 11:41:50 +02:00
|
|
|
|
|
|
|
|
|
|
internal static DateTime ReadTLStamp(this BinaryReader reader)
|
2021-10-17 03:18:36 +02:00
|
|
|
|
{
|
|
|
|
|
|
int unixstamp = reader.ReadInt32();
|
|
|
|
|
|
return unixstamp == int.MaxValue ? DateTime.MaxValue : new((unixstamp + 62135596800L) * 10000000, DateTimeKind.Utc);
|
|
|
|
|
|
}
|
2021-08-09 11:41:50 +02:00
|
|
|
|
|
|
|
|
|
|
internal static void WriteTLString(this BinaryWriter writer, string str)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (str == null)
|
|
|
|
|
|
writer.Write(0);
|
|
|
|
|
|
else
|
|
|
|
|
|
writer.WriteTLBytes(Encoding.UTF8.GetBytes(str));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static string ReadTLString(this BinaryReader reader)
|
|
|
|
|
|
=> Encoding.UTF8.GetString(reader.ReadTLBytes());
|
|
|
|
|
|
|
|
|
|
|
|
internal static void WriteTLBytes(this BinaryWriter writer, byte[] bytes)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
2021-08-09 11:41:50 +02:00
|
|
|
|
if (bytes == null) { writer.Write(0); return; }
|
2021-08-04 00:40:09 +02:00
|
|
|
|
int length = bytes.Length;
|
|
|
|
|
|
if (length < 254)
|
|
|
|
|
|
writer.Write((byte)length);
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2021-08-06 01:54:29 +02:00
|
|
|
|
writer.Write(length << 8 | 254);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
length += 3;
|
|
|
|
|
|
}
|
|
|
|
|
|
writer.Write(bytes);
|
|
|
|
|
|
while (++length % 4 != 0) writer.Write((byte)0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
internal static byte[] ReadTLBytes(this BinaryReader reader)
|
2021-08-04 00:40:09 +02:00
|
|
|
|
{
|
|
|
|
|
|
byte[] bytes;
|
|
|
|
|
|
int length = reader.ReadByte();
|
|
|
|
|
|
if (length < 254)
|
|
|
|
|
|
bytes = reader.ReadBytes(length);
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2021-09-18 02:30:12 +02:00
|
|
|
|
length = reader.ReadUInt16() + (reader.ReadByte() << 16);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
bytes = reader.ReadBytes(length);
|
|
|
|
|
|
length += 3;
|
|
|
|
|
|
}
|
|
|
|
|
|
while (++length % 4 != 0) reader.ReadByte();
|
|
|
|
|
|
return bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-09 11:41:50 +02:00
|
|
|
|
internal static void WriteTLNull(this BinaryWriter writer, Type type)
|
2021-08-07 06:23:13 +02:00
|
|
|
|
{
|
2021-09-27 03:25:28 +02:00
|
|
|
|
if (type == typeof(string)) { }
|
2021-09-30 03:40:08 +02:00
|
|
|
|
else if (!type.IsArray)
|
|
|
|
|
|
{
|
|
|
|
|
|
writer.Write(Layer.Nullables.TryGetValue(type, out uint nullCtor) ? nullCtor : Layer.NullCtor);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
2021-08-07 06:59:36 +02:00
|
|
|
|
else if (type != typeof(byte[]))
|
2021-09-27 03:25:28 +02:00
|
|
|
|
writer.Write(Layer.VectorCtor); // not raw bytes but a vector => needs a VectorCtor
|
|
|
|
|
|
writer.Write(0); // null arrays/strings are serialized as empty
|
2021-08-07 06:23:13 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-04-14 13:25:45 +02:00
|
|
|
|
internal static object ReadTLGzipped(this BinaryReader reader, Type type)
|
2024-03-28 12:13:56 +01:00
|
|
|
|
{
|
|
|
|
|
|
using var gzipReader = new BinaryReader(new GZipStream(new MemoryStream(reader.ReadTLBytes()), CompressionMode.Decompress));
|
2024-04-14 13:25:45 +02:00
|
|
|
|
return gzipReader.ReadTLValue(type);
|
2024-03-28 12:13:56 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
internal static bool ReadTLBool(this BinaryReader reader) => reader.ReadUInt32() switch
|
|
|
|
|
|
{
|
|
|
|
|
|
0x997275b5 => true,
|
|
|
|
|
|
0xbc799737 => false,
|
|
|
|
|
|
var value => throw new WTelegram.WTException($"Invalid boolean value #{value:x}")
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2021-08-04 00:40:09 +02:00
|
|
|
|
#if DEBUG
|
|
|
|
|
|
private static void ShouldntBeHere() => System.Diagnostics.Debugger.Break();
|
|
|
|
|
|
#else
|
|
|
|
|
|
private static void ShouldntBeHere() => throw new NotImplementedException("You've reached an unexpected point in code");
|
|
|
|
|
|
#endif
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public struct Int128
|
|
|
|
|
|
{
|
|
|
|
|
|
public byte[] raw;
|
|
|
|
|
|
|
2024-03-26 12:07:03 +01:00
|
|
|
|
public Int128(BinaryReader reader) => raw = reader.ReadBytes(16);
|
|
|
|
|
|
public Int128(RandomNumberGenerator rng) => rng.GetBytes(raw = new byte[16]);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
public static bool operator ==(Int128 left, Int128 right) { for (int i = 0; i < 16; i++) if (left.raw[i] != right.raw[i]) return false; return true; }
|
|
|
|
|
|
public static bool operator !=(Int128 left, Int128 right) { for (int i = 0; i < 16; i++) if (left.raw[i] != right.raw[i]) return true; return false; }
|
2023-07-08 01:34:31 +02:00
|
|
|
|
public override readonly bool Equals(object obj) => obj is Int128 other && this == other;
|
|
|
|
|
|
public override readonly int GetHashCode() => BitConverter.ToInt32(raw, 0);
|
|
|
|
|
|
public override readonly string ToString() => Convert.ToHexString(raw);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
public static implicit operator byte[](Int128 int128) => int128.raw;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public struct Int256
|
|
|
|
|
|
{
|
|
|
|
|
|
public byte[] raw;
|
|
|
|
|
|
|
2024-03-26 12:07:03 +01:00
|
|
|
|
public Int256(BinaryReader reader) => raw = reader.ReadBytes(32);
|
|
|
|
|
|
public Int256(RandomNumberGenerator rng) => rng.GetBytes(raw = new byte[32]);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
public static bool operator ==(Int256 left, Int256 right) { for (int i = 0; i < 32; i++) if (left.raw[i] != right.raw[i]) return false; return true; }
|
|
|
|
|
|
public static bool operator !=(Int256 left, Int256 right) { for (int i = 0; i < 32; i++) if (left.raw[i] != right.raw[i]) return true; return false; }
|
2023-07-08 01:34:31 +02:00
|
|
|
|
public override readonly bool Equals(object obj) => obj is Int256 other && this == other;
|
|
|
|
|
|
public override readonly int GetHashCode() => BitConverter.ToInt32(raw, 0);
|
|
|
|
|
|
public override readonly string ToString() => Convert.ToHexString(raw);
|
2021-08-04 00:40:09 +02:00
|
|
|
|
public static implicit operator byte[](Int256 int256) => int256.raw;
|
|
|
|
|
|
}
|
2021-08-20 14:45:39 +02:00
|
|
|
|
|
2024-03-29 16:42:58 +01:00
|
|
|
|
public sealed partial class UpdateAffectedMessages : Update // auto-generated for OnOwnUpdates in case of such API call result
|
2024-03-23 17:51:00 +01:00
|
|
|
|
{
|
2024-04-03 21:05:07 +02:00
|
|
|
|
public long mbox_id;
|
|
|
|
|
|
public int pts;
|
|
|
|
|
|
public int pts_count;
|
|
|
|
|
|
public override (long, int, int) GetMBox() => (mbox_id, pts, pts_count);
|
2024-03-28 12:13:56 +01:00
|
|
|
|
#if MTPG
|
|
|
|
|
|
public override void WriteTL(BinaryWriter writer) => throw new NotSupportedException();
|
|
|
|
|
|
#endif
|
2024-03-23 17:51:00 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-20 14:45:39 +02:00
|
|
|
|
// Below TL types are commented "parsed manually" from https://github.com/telegramdesktop/tdesktop/blob/dev/Telegram/Resources/tl/mtproto.tl
|
|
|
|
|
|
|
2022-02-11 18:05:12 +01:00
|
|
|
|
[TLDef(0x7A19CB76)] //RSA_public_key#7a19cb76 n:bytes e:bytes = RSAPublicKey
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class RSAPublicKey : IObject
|
2022-02-11 18:05:12 +01:00
|
|
|
|
{
|
|
|
|
|
|
public byte[] n;
|
|
|
|
|
|
public byte[] e;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2021-08-20 14:45:39 +02:00
|
|
|
|
[TLDef(0xF35C6D01)] //rpc_result#f35c6d01 req_msg_id:long result:Object = RpcResult
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class RpcResult : IObject
|
2021-08-20 14:45:39 +02:00
|
|
|
|
{
|
|
|
|
|
|
public long req_msg_id;
|
|
|
|
|
|
public object result;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[TLDef(0x5BB8E511)] //message#5bb8e511 msg_id:long seqno:int bytes:int body:Object = Message
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class _Message(long msgId, int seqNo, IObject obj) : IObject
|
2021-08-20 14:45:39 +02:00
|
|
|
|
{
|
2024-03-12 19:07:48 +01:00
|
|
|
|
public long msg_id = msgId;
|
|
|
|
|
|
public int seq_no = seqNo;
|
2021-08-20 14:45:39 +02:00
|
|
|
|
public int bytes;
|
2024-03-12 19:07:48 +01:00
|
|
|
|
public IObject body = obj;
|
2021-08-20 14:45:39 +02:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
[TLDef(0x73F1F8DC)] //msg_container#73f1f8dc messages:vector<%Message> = MessageContainer
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class MsgContainer : IObject { public _Message[] messages; }
|
2021-08-20 14:45:39 +02:00
|
|
|
|
[TLDef(0xE06046B2)] //msg_copy#e06046b2 orig_message:Message = MessageCopy
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class MsgCopy : IObject { public _Message orig_message; }
|
2021-08-20 14:45:39 +02:00
|
|
|
|
|
|
|
|
|
|
[TLDef(0x3072CFA1)] //gzip_packed#3072cfa1 packed_data:bytes = Object
|
2024-03-26 02:30:16 +01:00
|
|
|
|
public sealed partial class GzipPacked : IObject { public byte[] packed_data; }
|
2021-08-04 00:40:09 +02:00
|
|
|
|
}
|