using System; using System.CodeDom.Compiler; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Net; using System.Net.Cache; using System.Net.Security; using System.Reflection; using System.Reflection.Emit; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using System.Threading; using DynamicLinq; using ExIni; using Harmony; using ICSharpCode.SharpZipLib.Checksums; using ICSharpCode.SharpZipLib.Core; using ICSharpCode.SharpZipLib.Encryption; using ICSharpCode.SharpZipLib.Zip; using ICSharpCode.SharpZipLib.Zip.Compression; using ICSharpCode.SharpZipLib.Zip.Compression.Streams; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using UnityEngine; using UnityEngine.SceneManagement; using XUnity.AutoTranslator.Plugin.Core.AssetRedirection; using XUnity.AutoTranslator.Plugin.Core.Configuration; using XUnity.AutoTranslator.Plugin.Core.Debugging; using XUnity.AutoTranslator.Plugin.Core.Endpoints; using XUnity.AutoTranslator.Plugin.Core.Extensions; using XUnity.AutoTranslator.Plugin.Core.Fonts; using XUnity.AutoTranslator.Plugin.Core.Hooks; using XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI; using XUnity.AutoTranslator.Plugin.Core.Hooks.TextMeshPro; using XUnity.AutoTranslator.Plugin.Core.Hooks.UGUI; using XUnity.AutoTranslator.Plugin.Core.Hooks.UIElements; using XUnity.AutoTranslator.Plugin.Core.Managed.Textures; using XUnity.AutoTranslator.Plugin.Core.Parsing; using XUnity.AutoTranslator.Plugin.Core.Properties; using XUnity.AutoTranslator.Plugin.Core.Shims; using XUnity.AutoTranslator.Plugin.Core.Text; using XUnity.AutoTranslator.Plugin.Core.Textures; using XUnity.AutoTranslator.Plugin.Core.UI; using XUnity.AutoTranslator.Plugin.Core.UIResize; using XUnity.AutoTranslator.Plugin.Core.Utilities; using XUnity.AutoTranslator.Plugin.Core.Web; using XUnity.AutoTranslator.Plugin.Core.Web.Internal; using XUnity.AutoTranslator.Plugin.ExtProtocol; using XUnity.AutoTranslator.Plugin.Utilities; using XUnity.Common.Constants; using XUnity.Common.Extensions; using XUnity.Common.Harmony; using XUnity.Common.Logging; using XUnity.Common.MonoMod; using XUnity.Common.Utilities; using XUnity.ResourceRedirector; [assembly: AssemblyCopyright("Copyright © 2018 / MIT License")] [assembly: AssemblyTitle("XUnity.AutoTranslator.Plugin.Core")] [assembly: AssemblyProduct("XUnity.AutoTranslator.Plugin.Core")] [assembly: AssemblyInformationalVersion("5.6.1+7f1f3b9e8fc7d93a97734773804ba9c8fdf57714")] [assembly: AssemblyFileVersion("5.6.1.0")] [assembly: AssemblyDescription("Main development dependency for XUnity Auto Translator.")] [assembly: CompilationRelaxations(8)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("XUnity.AutoTranslator.Plugin.Core.Tests")] [assembly: AssemblyCompany("gravydevsupreme")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyConfiguration("Release")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("5.6.1.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [Microsoft.CodeAnalysis.Embedded] [CompilerGenerated] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DynamicLinq { internal static class DynamicQueryable { public static IQueryable Where(this IQueryable source, string predicate, params object[] values) { return (IQueryable)((IQueryable)source).Where(predicate, values); } public static IQueryable Where(this IQueryable source, string predicate, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (predicate == null) { throw new ArgumentNullException("predicate"); } LambdaExpression expression = DynamicExpression.ParseLambda(source.ElementType, typeof(bool), predicate, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Where", new Type[1] { source.ElementType }, source.Expression, Expression.Quote(expression))); } public static IQueryable Select(this IQueryable source, string selector, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (selector == null) { throw new ArgumentNullException("selector"); } LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, selector, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Select", new Type[2] { source.ElementType, lambdaExpression.Body.Type }, source.Expression, Expression.Quote(lambdaExpression))); } public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { return (IQueryable)((IQueryable)source).OrderBy(ordering, values); } public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (ordering == null) { throw new ArgumentNullException("ordering"); } ParameterExpression[] parameters = new ParameterExpression[1] { Expression.Parameter(source.ElementType, "") }; IEnumerable enumerable = new ExpressionParser(parameters, ordering, values).ParseOrdering(); Expression expression = source.Expression; string text = "OrderBy"; string text2 = "OrderByDescending"; foreach (DynamicOrdering item in enumerable) { expression = Expression.Call(typeof(Queryable), item.Ascending ? text : text2, new Type[2] { source.ElementType, item.Selector.Type }, expression, Expression.Quote(Expression.Lambda(item.Selector, parameters))); text = "ThenBy"; text2 = "ThenByDescending"; } return source.Provider.CreateQuery(expression); } public static IQueryable Take(this IQueryable source, int count) { if (source == null) { throw new ArgumentNullException("source"); } return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Take", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count))); } public static IQueryable Skip(this IQueryable source, int count) { if (source == null) { throw new ArgumentNullException("source"); } return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "Skip", new Type[1] { source.ElementType }, source.Expression, Expression.Constant(count))); } public static IQueryable GroupBy(this IQueryable source, string keySelector, string elementSelector, params object[] values) { if (source == null) { throw new ArgumentNullException("source"); } if (keySelector == null) { throw new ArgumentNullException("keySelector"); } if (elementSelector == null) { throw new ArgumentNullException("elementSelector"); } LambdaExpression lambdaExpression = DynamicExpression.ParseLambda(source.ElementType, null, keySelector, values); LambdaExpression lambdaExpression2 = DynamicExpression.ParseLambda(source.ElementType, null, elementSelector, values); return source.Provider.CreateQuery(Expression.Call(typeof(Queryable), "GroupBy", new Type[3] { source.ElementType, lambdaExpression.Body.Type, lambdaExpression2.Body.Type }, source.Expression, Expression.Quote(lambdaExpression), Expression.Quote(lambdaExpression2))); } public static bool Any(this IQueryable source) { if (source == null) { throw new ArgumentNullException("source"); } return (bool)source.Provider.Execute(Expression.Call(typeof(Queryable), "Any", new Type[1] { source.ElementType }, source.Expression)); } public static int Count(this IQueryable source) { if (source == null) { throw new ArgumentNullException("source"); } return (int)source.Provider.Execute(Expression.Call(typeof(Queryable), "Count", new Type[1] { source.ElementType }, source.Expression)); } } internal abstract class DynamicClass { public override string ToString() { PropertyInfo[] properties = GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public); StringBuilder stringBuilder = new StringBuilder(); stringBuilder.Append("{"); for (int i = 0; i < properties.Length; i++) { if (i > 0) { stringBuilder.Append(", "); } stringBuilder.Append(properties[i].Name); stringBuilder.Append("="); stringBuilder.Append(properties[i].GetValue(this, null)); } stringBuilder.Append("}"); return stringBuilder.ToString(); } } internal class DynamicProperty { private string name; private Type type; public string Name => name; public Type Type => type; public DynamicProperty(string name, Type type) { if (name == null) { throw new ArgumentNullException("name"); } if ((object)type == null) { throw new ArgumentNullException("type"); } this.name = name; this.type = type; } } internal static class DynamicExpression { public static Expression Parse(Type resultType, string expression, params object[] values) { return new ExpressionParser(null, expression, values).Parse(resultType); } public static LambdaExpression ParseLambda(Type itType, Type resultType, string expression, params object[] values) { return ParseLambda(new ParameterExpression[1] { Expression.Parameter(itType, "") }, resultType, expression, values); } public static LambdaExpression ParseLambda(ParameterExpression[] parameters, Type resultType, string expression, params object[] values) { return Expression.Lambda(new ExpressionParser(parameters, expression, values).Parse(resultType), parameters); } public static Expression> ParseLambda(string expression, params object[] values) { return (Expression>)ParseLambda(typeof(T), typeof(S), expression, values); } public static Type CreateClass(params DynamicProperty[] properties) { throw new NotImplementedException(); } public static Type CreateClass(IEnumerable properties) { throw new NotImplementedException(); } } internal class DynamicOrdering { public Expression Selector; public bool Ascending; } internal class Signature : IEquatable { public DynamicProperty[] properties; public int hashCode; public Signature(IEnumerable properties) { this.properties = properties.ToArray(); hashCode = 0; foreach (DynamicProperty property in properties) { hashCode ^= property.Name.GetHashCode() ^ property.Type.GetHashCode(); } } public override int GetHashCode() { return hashCode; } public override bool Equals(object obj) { if (!(obj is Signature)) { return false; } return Equals((Signature)obj); } public bool Equals(Signature other) { if (properties.Length != other.properties.Length) { return false; } for (int i = 0; i < properties.Length; i++) { if (properties[i].Name != other.properties[i].Name || (object)properties[i].Type != other.properties[i].Type) { return false; } } return true; } } internal sealed class ParseException : Exception { private int position; public int Position => position; public ParseException(string message, int position) : base(message) { this.position = position; } public override string ToString() { return $"{Message} (at index {position})"; } } internal class ExpressionParser { private struct Token { public TokenId id; public string text; public int pos; } private enum TokenId { Unknown, End, Identifier, StringLiteral, IntegerLiteral, RealLiteral, Exclamation, Percent, Amphersand, OpenParen, CloseParen, Asterisk, Plus, Comma, Minus, Dot, Slash, Colon, LessThan, Equal, GreaterThan, Question, OpenBracket, CloseBracket, Bar, ExclamationEqual, DoubleAmphersand, LessThanEqual, LessGreater, DoubleEqual, GreaterThanEqual, DoubleBar } private interface ILogicalSignatures { void F(bool x, bool y); void F(bool? x, bool? y); } private interface IArithmeticSignatures { void F(int x, int y); void F(uint x, uint y); void F(long x, long y); void F(ulong x, ulong y); void F(float x, float y); void F(double x, double y); void F(decimal x, decimal y); void F(int? x, int? y); void F(uint? x, uint? y); void F(long? x, long? y); void F(ulong? x, ulong? y); void F(float? x, float? y); void F(double? x, double? y); void F(decimal? x, decimal? y); } private interface IRelationalSignatures : IArithmeticSignatures { void F(string x, string y); void F(char x, char y); void F(DateTime x, DateTime y); void F(TimeSpan x, TimeSpan y); void F(char? x, char? y); void F(DateTime? x, DateTime? y); void F(TimeSpan? x, TimeSpan? y); } private interface IEqualitySignatures : IRelationalSignatures, IArithmeticSignatures { void F(bool x, bool y); void F(bool? x, bool? y); } private interface IAddSignatures : IArithmeticSignatures { void F(DateTime x, TimeSpan y); void F(TimeSpan x, TimeSpan y); void F(DateTime? x, TimeSpan? y); void F(TimeSpan? x, TimeSpan? y); } private interface ISubtractSignatures : IAddSignatures, IArithmeticSignatures { void F(DateTime x, DateTime y); void F(DateTime? x, DateTime? y); } private interface INegationSignatures { void F(int x); void F(long x); void F(float x); void F(double x); void F(decimal x); void F(int? x); void F(long? x); void F(float? x); void F(double? x); void F(decimal? x); } private interface INotSignatures { void F(bool x); void F(bool? x); } private interface IEnumerableSignatures { void Where(bool predicate); void Any(); void Any(bool predicate); void All(bool predicate); void Count(); void Count(bool predicate); void Min(object selector); void Max(object selector); void Sum(int selector); void Sum(int? selector); void Sum(long selector); void Sum(long? selector); void Sum(float selector); void Sum(float? selector); void Sum(double selector); void Sum(double? selector); void Sum(decimal selector); void Sum(decimal? selector); void Average(int selector); void Average(int? selector); void Average(long selector); void Average(long? selector); void Average(float selector); void Average(float? selector); void Average(double selector); void Average(double? selector); void Average(decimal selector); void Average(decimal? selector); } private class MethodData { public MethodBase MethodBase; public ParameterInfo[] Parameters; public Expression[] Args; } [CompilerGenerated] private sealed class d__78 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Type <>2__current; private int <>l__initialThreadId; private Type type; public Type <>3__type; Type IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__78(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; type = type.BaseType; break; } if ((object)type != null) { <>2__current = type; <>1__state = 1; return true; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__78 d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__78(0); } d__.type = <>3__type; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly Type[] predefinedTypes = new Type[20] { typeof(object), typeof(bool), typeof(char), typeof(string), typeof(sbyte), typeof(byte), typeof(short), typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal), typeof(DateTime), typeof(TimeSpan), typeof(Guid), typeof(Math), typeof(Convert) }; private static readonly Expression trueLiteral = Expression.Constant(true); private static readonly Expression falseLiteral = Expression.Constant(false); private static readonly Expression nullLiteral = Expression.Constant(null); private static readonly string keywordIt = "it"; private static readonly string keywordIif = "iif"; private static readonly string keywordNew = "new"; private static Dictionary keywords; private Dictionary symbols; private IDictionary externals; private Dictionary literals; private ParameterExpression it; private string text; private int textPos; private int textLen; private char ch; private Token token; public ExpressionParser(ParameterExpression[] parameters, string expression, object[] values) { if (expression == null) { throw new ArgumentNullException("expression"); } if (keywords == null) { keywords = CreateKeywords(); } symbols = new Dictionary(StringComparer.OrdinalIgnoreCase); literals = new Dictionary(); if (parameters != null) { ProcessParameters(parameters); } if (values != null) { ProcessValues(values); } text = expression; textLen = text.Length; SetTextPos(0); NextToken(); } private void ProcessParameters(ParameterExpression[] parameters) { foreach (ParameterExpression parameterExpression in parameters) { if (!string.IsNullOrEmpty(parameterExpression.Name)) { AddSymbol(parameterExpression.Name, parameterExpression); } } if (parameters.Length == 1 && string.IsNullOrEmpty(parameters[0].Name)) { it = parameters[0]; } } private void ProcessValues(object[] values) { for (int i = 0; i < values.Length; i++) { object obj = values[i]; if (i == values.Length - 1 && obj is IDictionary) { externals = (IDictionary)obj; } else { AddSymbol("@" + i.ToString(CultureInfo.InvariantCulture), obj); } } } private void AddSymbol(string name, object value) { if (symbols.ContainsKey(name)) { throw ParseError("The identifier '{0}' was defined more than once", name); } symbols.Add(name, value); } public Expression Parse(Type resultType) { int pos = token.pos; Expression expression = ParseExpression(); if ((object)resultType != null && (expression = PromoteExpression(expression, resultType, exact: true)) == null) { throw ParseError(pos, "Expression of type '{0}' expected", GetTypeName(resultType)); } ValidateToken(TokenId.End, "Syntax error"); return expression; } public IEnumerable ParseOrdering() { List list = new List(); while (true) { Expression selector = ParseExpression(); bool ascending = true; if (TokenIdentifierIs("asc") || TokenIdentifierIs("ascending")) { NextToken(); } else if (TokenIdentifierIs("desc") || TokenIdentifierIs("descending")) { NextToken(); ascending = false; } list.Add(new DynamicOrdering { Selector = selector, Ascending = ascending }); if (token.id != TokenId.Comma) { break; } NextToken(); } ValidateToken(TokenId.End, "Syntax error"); return list; } private Expression ParseExpression() { int pos = token.pos; Expression expression = ParseLogicalOr(); if (token.id == TokenId.Question) { NextToken(); Expression expr = ParseExpression(); ValidateToken(TokenId.Colon, "':' expected"); NextToken(); Expression expr2 = ParseExpression(); expression = GenerateConditional(expression, expr, expr2, pos); } return expression; } private Expression ParseLogicalOr() { Expression left = ParseLogicalAnd(); while (this.token.id == TokenId.DoubleBar || TokenIdentifierIs("or")) { Token token = this.token; NextToken(); Expression right = ParseLogicalAnd(); CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos); left = Expression.OrElse(left, right); } return left; } private Expression ParseLogicalAnd() { Expression left = ParseComparison(); while (this.token.id == TokenId.DoubleAmphersand || TokenIdentifierIs("and")) { Token token = this.token; NextToken(); Expression right = ParseComparison(); CheckAndPromoteOperands(typeof(ILogicalSignatures), token.text, ref left, ref right, token.pos); left = Expression.AndAlso(left, right); } return left; } private Expression ParseComparison() { Expression left = ParseAdditive(); while (this.token.id == TokenId.Equal || this.token.id == TokenId.DoubleEqual || this.token.id == TokenId.ExclamationEqual || this.token.id == TokenId.LessGreater || this.token.id == TokenId.GreaterThan || this.token.id == TokenId.GreaterThanEqual || this.token.id == TokenId.LessThan || this.token.id == TokenId.LessThanEqual) { Token token = this.token; NextToken(); Expression right = ParseAdditive(); bool flag = token.id == TokenId.Equal || token.id == TokenId.DoubleEqual || token.id == TokenId.ExclamationEqual || token.id == TokenId.LessGreater; if (flag && !left.Type.IsValueType && !right.Type.IsValueType) { if ((object)left.Type != right.Type) { if (left.Type.IsAssignableFrom(right.Type)) { right = Expression.Convert(right, left.Type); } else { if (!right.Type.IsAssignableFrom(left.Type)) { throw IncompatibleOperandsError(token.text, left, right, token.pos); } left = Expression.Convert(left, right.Type); } } } else if (IsEnumType(left.Type) || IsEnumType(right.Type)) { if ((object)left.Type != right.Type) { Expression expression; if ((expression = PromoteExpression(right, left.Type, exact: true)) != null) { right = expression; } else { if ((expression = PromoteExpression(left, right.Type, exact: true)) == null) { throw IncompatibleOperandsError(token.text, left, right, token.pos); } left = expression; } } } else { CheckAndPromoteOperands(flag ? typeof(IEqualitySignatures) : typeof(IRelationalSignatures), token.text, ref left, ref right, token.pos); } switch (token.id) { case TokenId.Equal: case TokenId.DoubleEqual: left = GenerateEqual(left, right); break; case TokenId.ExclamationEqual: case TokenId.LessGreater: left = GenerateNotEqual(left, right); break; case TokenId.GreaterThan: left = GenerateGreaterThan(left, right); break; case TokenId.GreaterThanEqual: left = GenerateGreaterThanEqual(left, right); break; case TokenId.LessThan: left = GenerateLessThan(left, right); break; case TokenId.LessThanEqual: left = GenerateLessThanEqual(left, right); break; } } return left; } private Expression ParseAdditive() { Expression left = ParseMultiplicative(); while (this.token.id == TokenId.Plus || this.token.id == TokenId.Minus || this.token.id == TokenId.Amphersand) { Token token = this.token; NextToken(); Expression right = ParseMultiplicative(); TokenId id = token.id; if (id != TokenId.Amphersand) { if (id != TokenId.Plus) { if (id == TokenId.Minus) { CheckAndPromoteOperands(typeof(ISubtractSignatures), token.text, ref left, ref right, token.pos); left = GenerateSubtract(left, right); } continue; } if ((object)left.Type != typeof(string) && (object)right.Type != typeof(string)) { CheckAndPromoteOperands(typeof(IAddSignatures), token.text, ref left, ref right, token.pos); left = GenerateAdd(left, right); continue; } } left = GenerateStringConcat(left, right); } return left; } private Expression ParseMultiplicative() { Expression left = ParseUnary(); while (this.token.id == TokenId.Asterisk || this.token.id == TokenId.Slash || this.token.id == TokenId.Percent || TokenIdentifierIs("mod")) { Token token = this.token; NextToken(); Expression right = ParseUnary(); CheckAndPromoteOperands(typeof(IArithmeticSignatures), token.text, ref left, ref right, token.pos); switch (token.id) { case TokenId.Asterisk: left = Expression.Multiply(left, right); break; case TokenId.Slash: left = Expression.Divide(left, right); break; case TokenId.Identifier: case TokenId.Percent: left = Expression.Modulo(left, right); break; } } return left; } private Expression ParseUnary() { if (this.token.id == TokenId.Minus || this.token.id == TokenId.Exclamation || TokenIdentifierIs("not")) { Token token = this.token; NextToken(); if (token.id == TokenId.Minus && (this.token.id == TokenId.IntegerLiteral || this.token.id == TokenId.RealLiteral)) { this.token.text = "-" + this.token.text; this.token.pos = token.pos; return ParsePrimary(); } Expression expr = ParseUnary(); if (token.id == TokenId.Minus) { CheckAndPromoteOperand(typeof(INegationSignatures), token.text, ref expr, token.pos); return Expression.Negate(expr); } CheckAndPromoteOperand(typeof(INotSignatures), token.text, ref expr, token.pos); return Expression.Not(expr); } return ParsePrimary(); } private Expression ParsePrimary() { Expression expression = ParsePrimaryStart(); while (true) { if (token.id == TokenId.Dot) { NextToken(); expression = ParseMemberAccess(null, expression); continue; } if (token.id != TokenId.OpenBracket) { break; } expression = ParseElementAccess(expression); } return expression; } private Expression ParsePrimaryStart() { return token.id switch { TokenId.Identifier => ParseIdentifier(), TokenId.StringLiteral => ParseStringLiteral(), TokenId.IntegerLiteral => ParseIntegerLiteral(), TokenId.RealLiteral => ParseRealLiteral(), TokenId.OpenParen => ParseParenExpression(), _ => throw ParseError("Expression expected"), }; } private Expression ParseStringLiteral() { ValidateToken(TokenId.StringLiteral); char c = token.text[0]; string text = token.text.Substring(1, token.text.Length - 2); int startIndex = 0; while (true) { int num = text.IndexOf(c, startIndex); if (num < 0) { break; } text = text.Remove(num, 1); startIndex = num + 1; } if (c == '\'') { if (text.Length != 1) { throw ParseError("Character literal must contain exactly one character"); } NextToken(); return CreateLiteral(text[0], text); } NextToken(); return CreateLiteral(text, text); } private Expression ParseIntegerLiteral() { ValidateToken(TokenId.IntegerLiteral); string text = token.text; if (text[0] != '-') { if (!ulong.TryParse(text, out var result)) { throw ParseError("Invalid integer literal '{0}'", text); } NextToken(); if (result <= int.MaxValue) { return CreateLiteral((int)result, text); } if (result <= uint.MaxValue) { return CreateLiteral((uint)result, text); } if (result <= long.MaxValue) { return CreateLiteral((long)result, text); } return CreateLiteral(result, text); } if (!long.TryParse(text, out var result2)) { throw ParseError("Invalid integer literal '{0}'", text); } NextToken(); if (result2 >= int.MinValue && result2 <= int.MaxValue) { return CreateLiteral((int)result2, text); } return CreateLiteral(result2, text); } private Expression ParseRealLiteral() { ValidateToken(TokenId.RealLiteral); string text = token.text; object obj = null; char c = text[text.Length - 1]; double result2; if (c == 'F' || c == 'f') { if (float.TryParse(text.Substring(0, text.Length - 1), out var result)) { obj = result; } } else if (double.TryParse(text, out result2)) { obj = result2; } if (obj == null) { throw ParseError("Invalid real literal '{0}'", text); } NextToken(); return CreateLiteral(obj, text); } private Expression CreateLiteral(object value, string text) { ConstantExpression constantExpression = Expression.Constant(value); literals.Add(constantExpression, text); return constantExpression; } private Expression ParseParenExpression() { ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); Expression result = ParseExpression(); ValidateToken(TokenId.CloseParen, "')' or operator expected"); NextToken(); return result; } private Expression ParseIdentifier() { ValidateToken(TokenId.Identifier); if (keywords.TryGetValue(token.text, out var value)) { if (value is Type) { return ParseTypeAccess((Type)value); } if (value == keywordIt) { return ParseIt(); } if (value == keywordIif) { return ParseIif(); } if (value == keywordNew) { return ParseNew(); } NextToken(); return (Expression)value; } if (symbols.TryGetValue(token.text, out value) || (externals != null && externals.TryGetValue(token.text, out value))) { Expression expression = value as Expression; if (expression == null) { expression = Expression.Constant(value); } else if (expression is LambdaExpression lambda) { return ParseLambdaInvocation(lambda); } NextToken(); return expression; } if (it != null) { return ParseMemberAccess(null, it); } throw ParseError("Unknown identifier '{0}'", token.text); } private Expression ParseIt() { if (it == null) { throw ParseError("No 'it' is in scope"); } NextToken(); return it; } private Expression ParseIif() { int pos = token.pos; NextToken(); Expression[] array = ParseArgumentList(); if (array.Length != 3) { throw ParseError(pos, "The 'iif' function requires three arguments"); } return GenerateConditional(array[0], array[1], array[2], pos); } private Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) { if ((object)test.Type != typeof(bool)) { throw ParseError(errorPos, "The first expression must be of type 'Boolean'"); } if ((object)expr1.Type != expr2.Type) { Expression expression = ((expr2 != nullLiteral) ? PromoteExpression(expr1, expr2.Type, exact: true) : null); Expression expression2 = ((expr1 != nullLiteral) ? PromoteExpression(expr2, expr1.Type, exact: true) : null); if (expression != null && expression2 == null) { expr1 = expression; } else { if (expression2 == null || expression != null) { string text = ((expr1 != nullLiteral) ? expr1.Type.Name : "null"); string text2 = ((expr2 != nullLiteral) ? expr2.Type.Name : "null"); if (expression != null && expression2 != null) { throw ParseError(errorPos, "Both of the types '{0}' and '{1}' convert to the other", text, text2); } throw ParseError(errorPos, "Neither of the types '{0}' and '{1}' converts to the other", text, text2); } expr2 = expression2; } } return Expression.Condition(test, expr1, expr2); } private Expression ParseNew() { NextToken(); ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); List list = new List(); List list2 = new List(); while (true) { int pos = token.pos; Expression expression = ParseExpression(); string name; if (TokenIdentifierIs("as")) { NextToken(); name = GetIdentifier(); NextToken(); } else { if (!(expression is MemberExpression memberExpression)) { throw ParseError(pos, "Expression is missing an 'as' clause"); } name = memberExpression.Member.Name; } list2.Add(expression); list.Add(new DynamicProperty(name, expression.Type)); if (token.id != TokenId.Comma) { break; } NextToken(); } ValidateToken(TokenId.CloseParen, "')' or ',' expected"); NextToken(); Type type = DynamicExpression.CreateClass(list); MemberBinding[] array = new MemberBinding[list.Count]; for (int i = 0; i < array.Length; i++) { array[i] = Expression.Bind(type.GetProperty(list[i].Name), list2[i]); } return Expression.MemberInit(Expression.New(type), array); } private Expression ParseLambdaInvocation(LambdaExpression lambda) { int pos = token.pos; NextToken(); Expression[] array = ParseArgumentList(); if (FindMethod(lambda.Type, "Invoke", staticAccess: false, array, out var _) != 1) { throw ParseError(pos, "Argument list incompatible with lambda expression"); } return Expression.Invoke(lambda, array); } private Expression ParseTypeAccess(Type type) { int pos = token.pos; NextToken(); if (token.id == TokenId.Question) { if (!type.IsValueType || IsNullableType(type)) { throw ParseError(pos, "Type '{0}' has no nullable form", GetTypeName(type)); } type = typeof(Nullable<>).MakeGenericType(type); NextToken(); } if (token.id == TokenId.OpenParen) { Expression[] array = ParseArgumentList(); MethodBase method; switch (FindBestMethod(type.GetConstructors(), array, out method)) { case 0: if (array.Length == 1) { return GenerateConversion(array[0], type, pos); } throw ParseError(pos, "No matching constructor in type '{0}'", GetTypeName(type)); case 1: return Expression.New((ConstructorInfo)method, array); default: throw ParseError(pos, "Ambiguous invocation of '{0}' constructor", GetTypeName(type)); } } ValidateToken(TokenId.Dot, "'.' or '(' expected"); NextToken(); return ParseMemberAccess(type, null); } private Expression GenerateConversion(Expression expr, Type type, int errorPos) { Type type2 = expr.Type; if ((object)type2 == type) { return expr; } if (type2.IsValueType && type.IsValueType) { if ((IsNullableType(type2) || IsNullableType(type)) && (object)GetNonNullableType(type2) == GetNonNullableType(type)) { return Expression.Convert(expr, type); } if (((IsNumericType(type2) || IsEnumType(type2)) && IsNumericType(type)) || IsEnumType(type)) { return Expression.ConvertChecked(expr, type); } } if (type2.IsAssignableFrom(type) || type.IsAssignableFrom(type2) || type2.IsInterface || type.IsInterface) { return Expression.Convert(expr, type); } throw ParseError(errorPos, "A value of type '{0}' cannot be converted to type '{1}'", GetTypeName(type2), GetTypeName(type)); } private Expression ParseMemberAccess(Type type, Expression instance) { if (instance != null) { type = instance.Type; } int pos = token.pos; string identifier = GetIdentifier(); NextToken(); if (token.id == TokenId.OpenParen) { if (instance != null && (object)type != typeof(string)) { Type type2 = FindGenericType(typeof(IEnumerable<>), type); if ((object)type2 != null) { Type elementType = type2.GetGenericArguments()[0]; return ParseAggregate(instance, elementType, identifier, pos); } } Expression[] array = ParseArgumentList(); MethodBase method; switch (FindMethod(type, identifier, instance == null, array, out method)) { case 0: throw ParseError(pos, "No applicable method '{0}' exists in type '{1}'", identifier, GetTypeName(type)); case 1: { MethodInfo methodInfo = (MethodInfo)method; if (!IsPredefinedType(methodInfo.DeclaringType)) { throw ParseError(pos, "Methods on type '{0}' are not accessible", GetTypeName(methodInfo.DeclaringType)); } if ((object)methodInfo.ReturnType == typeof(void)) { throw ParseError(pos, "Method '{0}' in type '{1}' does not return a value", identifier, GetTypeName(methodInfo.DeclaringType)); } return Expression.Call(instance, methodInfo, array); } default: throw ParseError(pos, "Ambiguous invocation of method '{0}' in type '{1}'", identifier, GetTypeName(type)); } } MemberInfo memberInfo = FindPropertyOrField(type, identifier, instance == null); if ((object)memberInfo == null) { throw ParseError(pos, "No property or field '{0}' exists in type '{1}'", identifier, GetTypeName(type)); } if (!(memberInfo is PropertyInfo)) { return Expression.Field(instance, (FieldInfo)memberInfo); } return Expression.Property(instance, (PropertyInfo)memberInfo); } private static Type FindGenericType(Type generic, Type type) { while ((object)type != null && (object)type != typeof(object)) { if (type.IsGenericType && (object)type.GetGenericTypeDefinition() == generic) { return type; } if (generic.IsInterface) { Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { Type type3 = FindGenericType(generic, type2); if ((object)type3 != null) { return type3; } } } type = type.BaseType; } return null; } private Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos) { ParameterExpression parameterExpression = it; ParameterExpression parameterExpression2 = (it = Expression.Parameter(elementType, "")); Expression[] array = ParseArgumentList(); it = parameterExpression; if (FindMethod(typeof(IEnumerableSignatures), methodName, staticAccess: false, array, out var method) != 1) { throw ParseError(errorPos, "No applicable aggregate method '{0}' exists", methodName); } return Expression.Call(typeArguments: (!(method.Name == "Min") && !(method.Name == "Max")) ? new Type[1] { elementType } : new Type[2] { elementType, array[0].Type }, arguments: (array.Length != 0) ? new Expression[2] { instance, Expression.Lambda(array[0], parameterExpression2) } : new Expression[1] { instance }, type: typeof(Enumerable), methodName: method.Name); } private Expression[] ParseArgumentList() { ValidateToken(TokenId.OpenParen, "'(' expected"); NextToken(); Expression[] result = ((token.id != TokenId.CloseParen) ? ParseArguments() : new Expression[0]); ValidateToken(TokenId.CloseParen, "')' or ',' expected"); NextToken(); return result; } private Expression[] ParseArguments() { List list = new List(); while (true) { list.Add(ParseExpression()); if (token.id != TokenId.Comma) { break; } NextToken(); } return list.ToArray(); } private Expression ParseElementAccess(Expression expr) { int pos = token.pos; ValidateToken(TokenId.OpenBracket, "'(' expected"); NextToken(); Expression[] array = ParseArguments(); ValidateToken(TokenId.CloseBracket, "']' or ',' expected"); NextToken(); if (expr.Type.IsArray) { if (expr.Type.GetArrayRank() != 1 || array.Length != 1) { throw ParseError(pos, "Indexing of multi-dimensional arrays is not supported"); } Expression expression = PromoteExpression(array[0], typeof(int), exact: true); if (expression == null) { throw ParseError(pos, "Array index must be an integer expression"); } return Expression.ArrayIndex(expr, expression); } MethodBase method; return FindIndexer(expr.Type, array, out method) switch { 0 => throw ParseError(pos, "No applicable indexer exists in type '{0}'", GetTypeName(expr.Type)), 1 => Expression.Call(expr, (MethodInfo)method, array), _ => throw ParseError(pos, "Ambiguous invocation of indexer in type '{0}'", GetTypeName(expr.Type)), }; } private static bool IsPredefinedType(Type type) { Type[] array = predefinedTypes; for (int i = 0; i < array.Length; i++) { if ((object)array[i] == type) { return true; } } return false; } private static bool IsNullableType(Type type) { if (type.IsGenericType) { return (object)type.GetGenericTypeDefinition() == typeof(Nullable<>); } return false; } private static Type GetNonNullableType(Type type) { if (!IsNullableType(type)) { return type; } return type.GetGenericArguments()[0]; } private static string GetTypeName(Type type) { Type nonNullableType = GetNonNullableType(type); string text = nonNullableType.Name; if ((object)type != nonNullableType) { text += "?"; } return text; } private static bool IsNumericType(Type type) { return GetNumericTypeKind(type) != 0; } private static bool IsSignedIntegralType(Type type) { return GetNumericTypeKind(type) == 2; } private static bool IsUnsignedIntegralType(Type type) { return GetNumericTypeKind(type) == 3; } private static int GetNumericTypeKind(Type type) { type = GetNonNullableType(type); if (type.IsEnum) { return 0; } switch (Type.GetTypeCode(type)) { case TypeCode.Char: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return 1; case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: return 2; case TypeCode.Byte: case TypeCode.UInt16: case TypeCode.UInt32: case TypeCode.UInt64: return 3; default: return 0; } } private static bool IsEnumType(Type type) { return GetNonNullableType(type).IsEnum; } private void CheckAndPromoteOperand(Type signatures, string opName, ref Expression expr, int errorPos) { Expression[] array = new Expression[1] { expr }; if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1) { throw ParseError(errorPos, "Operator '{0}' incompatible with operand type '{1}'", opName, GetTypeName(array[0].Type)); } expr = array[0]; } private void CheckAndPromoteOperands(Type signatures, string opName, ref Expression left, ref Expression right, int errorPos) { Expression[] array = new Expression[2] { left, right }; if (FindMethod(signatures, "F", staticAccess: false, array, out var _) != 1) { throw IncompatibleOperandsError(opName, left, right, errorPos); } left = array[0]; right = array[1]; } private Exception IncompatibleOperandsError(string opName, Expression left, Expression right, int pos) { return ParseError(pos, "Operator '{0}' incompatible with operand types '{1}' and '{2}'", opName, GetTypeName(left.Type), GetTypeName(right.Type)); } private MemberInfo FindPropertyOrField(Type type, string memberName, bool staticAccess) { BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] array = item.FindMembers(MemberTypes.Field | MemberTypes.Property, bindingAttr, Type.FilterNameIgnoreCase, memberName); if (array.Length != 0) { return array[0]; } } return null; } private int FindMethod(Type type, string methodName, bool staticAccess, Expression[] args, out MethodBase method) { BindingFlags bindingAttr = BindingFlags.DeclaredOnly | BindingFlags.Public | (staticAccess ? BindingFlags.Static : BindingFlags.Instance); foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] source = item.FindMembers(MemberTypes.Method, bindingAttr, Type.FilterNameIgnoreCase, methodName); int num = FindBestMethod(source.Cast(), args, out method); if (num != 0) { return num; } } method = null; return 0; } private int FindIndexer(Type type, Expression[] args, out MethodBase method) { foreach (Type item in SelfAndBaseTypes(type)) { MemberInfo[] defaultMembers = item.GetDefaultMembers(); if (defaultMembers.Length != 0) { IEnumerable methods = from m in defaultMembers.OfType().Select((Func)((PropertyInfo p) => p.GetGetMethod())) where (object)m != null select m; int num = FindBestMethod(methods, args, out method); if (num != 0) { return num; } } } method = null; return 0; } private static IEnumerable SelfAndBaseTypes(Type type) { if (type.IsInterface) { List list = new List(); AddInterface(list, type); return list; } return SelfAndBaseClasses(type); } private static IEnumerable SelfAndBaseClasses(Type type) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__78(-2) { <>3__type = type }; } private static void AddInterface(List types, Type type) { if (!types.Contains(type)) { types.Add(type); Type[] interfaces = type.GetInterfaces(); foreach (Type type2 in interfaces) { AddInterface(types, type2); } } } private int FindBestMethod(IEnumerable methods, Expression[] args, out MethodBase method) { MethodData[] applicable = (from m in methods select new MethodData { MethodBase = m, Parameters = m.GetParameters() } into m where IsApplicable(m, args) select m).ToArray(); if (applicable.Length > 1) { applicable = applicable.Where((MethodData m) => applicable.All((MethodData n) => m == n || IsBetterThan(args, m, n))).ToArray(); } if (applicable.Length == 1) { MethodData methodData = applicable[0]; for (int i = 0; i < args.Length; i++) { args[i] = methodData.Args[i]; } method = methodData.MethodBase; } else { method = null; } return applicable.Length; } private bool IsApplicable(MethodData method, Expression[] args) { if (method.Parameters.Length != args.Length) { return false; } Expression[] array = new Expression[args.Length]; for (int i = 0; i < args.Length; i++) { ParameterInfo parameterInfo = method.Parameters[i]; if (parameterInfo.IsOut) { return false; } Expression expression = PromoteExpression(args[i], parameterInfo.ParameterType, exact: false); if (expression == null) { return false; } array[i] = expression; } method.Args = array; return true; } private Expression PromoteExpression(Expression expr, Type type, bool exact) { if ((object)expr.Type == type) { return expr; } if (expr is ConstantExpression) { ConstantExpression constantExpression = (ConstantExpression)expr; string value; if (constantExpression == nullLiteral) { if (!type.IsValueType || IsNullableType(type)) { return Expression.Constant(null, type); } } else if (literals.TryGetValue(constantExpression, out value)) { Type nonNullableType = GetNonNullableType(type); object obj = null; switch (Type.GetTypeCode(constantExpression.Type)) { case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: obj = ParseNumber(value, nonNullableType); break; case TypeCode.Double: if ((object)nonNullableType == typeof(decimal)) { obj = ParseNumber(value, nonNullableType); } break; case TypeCode.String: obj = ParseEnum(value, nonNullableType); break; } if (obj != null) { return Expression.Constant(obj, type); } } } if (IsCompatibleWith(expr.Type, type)) { if (type.IsValueType || exact) { return Expression.Convert(expr, type); } return expr; } return null; } private static object ParseNumber(string text, Type type) { switch (Type.GetTypeCode(GetNonNullableType(type))) { case TypeCode.SByte: { if (sbyte.TryParse(text, out var result6)) { return result6; } break; } case TypeCode.Byte: { if (byte.TryParse(text, out var result10)) { return result10; } break; } case TypeCode.Int16: { if (short.TryParse(text, out var result2)) { return result2; } break; } case TypeCode.UInt16: { if (ushort.TryParse(text, out var result8)) { return result8; } break; } case TypeCode.Int32: { if (int.TryParse(text, out var result4)) { return result4; } break; } case TypeCode.UInt32: { if (uint.TryParse(text, out var result11)) { return result11; } break; } case TypeCode.Int64: { if (long.TryParse(text, out var result9)) { return result9; } break; } case TypeCode.UInt64: { if (ulong.TryParse(text, out var result7)) { return result7; } break; } case TypeCode.Single: { if (float.TryParse(text, out var result5)) { return result5; } break; } case TypeCode.Double: { if (double.TryParse(text, out var result3)) { return result3; } break; } case TypeCode.Decimal: { if (decimal.TryParse(text, out var result)) { return result; } break; } } return null; } private static object ParseEnum(string name, Type type) { if (type.IsEnum) { MemberInfo[] array = type.FindMembers(MemberTypes.Field, BindingFlags.DeclaredOnly | BindingFlags.Static | BindingFlags.Public, Type.FilterNameIgnoreCase, name); if (array.Length != 0) { return ((FieldInfo)array[0]).GetValue(null); } } return null; } private static bool IsCompatibleWith(Type source, Type target) { if ((object)source == target) { return true; } if (!target.IsValueType) { return target.IsAssignableFrom(source); } Type nonNullableType = GetNonNullableType(source); Type nonNullableType2 = GetNonNullableType(target); if ((object)nonNullableType != source && (object)nonNullableType2 == target) { return false; } TypeCode typeCode = (nonNullableType.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType)); TypeCode typeCode2 = (nonNullableType2.IsEnum ? TypeCode.Object : Type.GetTypeCode(nonNullableType2)); switch (typeCode) { case TypeCode.SByte: switch (typeCode2) { case TypeCode.SByte: case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.Byte: if ((uint)(typeCode2 - 6) <= 9u) { return true; } break; case TypeCode.Int16: switch (typeCode2) { case TypeCode.Int16: case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt16: if ((uint)(typeCode2 - 8) <= 7u) { return true; } break; case TypeCode.Int32: switch (typeCode2) { case TypeCode.Int32: case TypeCode.Int64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: return true; } break; case TypeCode.UInt32: if ((uint)(typeCode2 - 10) <= 5u) { return true; } break; case TypeCode.Int64: if (typeCode2 == TypeCode.Int64 || (uint)(typeCode2 - 13) <= 2u) { return true; } break; case TypeCode.UInt64: if ((uint)(typeCode2 - 12) <= 3u) { return true; } break; case TypeCode.Single: if ((uint)(typeCode2 - 13) <= 1u) { return true; } break; default: if ((object)nonNullableType == nonNullableType2) { return true; } break; } return false; } private static bool IsBetterThan(Expression[] args, MethodData m1, MethodData m2) { bool result = false; for (int i = 0; i < args.Length; i++) { int num = CompareConversions(args[i].Type, m1.Parameters[i].ParameterType, m2.Parameters[i].ParameterType); if (num < 0) { return false; } if (num > 0) { result = true; } } return result; } private static int CompareConversions(Type s, Type t1, Type t2) { if ((object)t1 == t2) { return 0; } if ((object)s == t1) { return 1; } if ((object)s == t2) { return -1; } bool flag = IsCompatibleWith(t1, t2); bool flag2 = IsCompatibleWith(t2, t1); if (flag && !flag2) { return 1; } if (flag2 && !flag) { return -1; } if (IsSignedIntegralType(t1) && IsUnsignedIntegralType(t2)) { return 1; } if (IsSignedIntegralType(t2) && IsUnsignedIntegralType(t1)) { return -1; } return 0; } private Expression GenerateEqual(Expression left, Expression right) { return Expression.Equal(left, right); } private Expression GenerateNotEqual(Expression left, Expression right) { return Expression.NotEqual(left, right); } private Expression GenerateGreaterThan(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.GreaterThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.GreaterThan(left, right); } private Expression GenerateGreaterThanEqual(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.GreaterThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.GreaterThanOrEqual(left, right); } private Expression GenerateLessThan(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.LessThan(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.LessThan(left, right); } private Expression GenerateLessThanEqual(Expression left, Expression right) { if ((object)left.Type == typeof(string)) { return Expression.LessThanOrEqual(GenerateStaticMethodCall("Compare", left, right), Expression.Constant(0)); } return Expression.LessThanOrEqual(left, right); } private Expression GenerateAdd(Expression left, Expression right) { if ((object)left.Type == typeof(string) && (object)right.Type == typeof(string)) { return GenerateStaticMethodCall("Concat", left, right); } return Expression.Add(left, right); } private Expression GenerateSubtract(Expression left, Expression right) { return Expression.Subtract(left, right); } private Expression GenerateStringConcat(Expression left, Expression right) { return Expression.Call(null, typeof(string).GetMethod("Concat", new Type[2] { typeof(object), typeof(object) }), new Expression[2] { left, right }); } private MethodInfo GetStaticMethod(string methodName, Expression left, Expression right) { return left.Type.GetMethod(methodName, new Type[2] { left.Type, right.Type }); } private Expression GenerateStaticMethodCall(string methodName, Expression left, Expression right) { return Expression.Call(null, GetStaticMethod(methodName, left, right), new Expression[2] { left, right }); } private void SetTextPos(int pos) { textPos = pos; ch = ((textPos < textLen) ? text[textPos] : '\0'); } private void NextChar() { if (textPos < textLen) { textPos++; } ch = ((textPos < textLen) ? text[textPos] : '\0'); } private void NextToken() { while (char.IsWhiteSpace(ch)) { NextChar(); } int num = textPos; TokenId id; switch (ch) { case '!': NextChar(); if (ch == '=') { NextChar(); id = TokenId.ExclamationEqual; } else { id = TokenId.Exclamation; } break; case '%': NextChar(); id = TokenId.Percent; break; case '&': NextChar(); if (ch == '&') { NextChar(); id = TokenId.DoubleAmphersand; } else { id = TokenId.Amphersand; } break; case '(': NextChar(); id = TokenId.OpenParen; break; case ')': NextChar(); id = TokenId.CloseParen; break; case '*': NextChar(); id = TokenId.Asterisk; break; case '+': NextChar(); id = TokenId.Plus; break; case ',': NextChar(); id = TokenId.Comma; break; case '-': NextChar(); id = TokenId.Minus; break; case '.': NextChar(); id = TokenId.Dot; break; case '/': NextChar(); id = TokenId.Slash; break; case ':': NextChar(); id = TokenId.Colon; break; case '<': NextChar(); if (ch == '=') { NextChar(); id = TokenId.LessThanEqual; } else if (ch == '>') { NextChar(); id = TokenId.LessGreater; } else { id = TokenId.LessThan; } break; case '=': NextChar(); if (ch == '=') { NextChar(); id = TokenId.DoubleEqual; } else { id = TokenId.Equal; } break; case '>': NextChar(); if (ch == '=') { NextChar(); id = TokenId.GreaterThanEqual; } else { id = TokenId.GreaterThan; } break; case '?': NextChar(); id = TokenId.Question; break; case '[': NextChar(); id = TokenId.OpenBracket; break; case ']': NextChar(); id = TokenId.CloseBracket; break; case '|': NextChar(); if (ch == '|') { NextChar(); id = TokenId.DoubleBar; } else { id = TokenId.Bar; } break; case '"': case '\'': { char c = ch; do { NextChar(); while (textPos < textLen && ch != c) { NextChar(); } if (textPos == textLen) { throw ParseError(textPos, "Unterminated string literal"); } NextChar(); } while (ch == c); id = TokenId.StringLiteral; break; } default: if (char.IsLetter(ch) || ch == '@' || ch == '_') { do { NextChar(); } while (char.IsLetterOrDigit(ch) || ch == '_'); id = TokenId.Identifier; } else if (char.IsDigit(ch)) { id = TokenId.IntegerLiteral; do { NextChar(); } while (char.IsDigit(ch)); if (ch == '.') { id = TokenId.RealLiteral; NextChar(); ValidateDigit(); do { NextChar(); } while (char.IsDigit(ch)); } if (ch == 'E' || ch == 'e') { id = TokenId.RealLiteral; NextChar(); if (ch == '+' || ch == '-') { NextChar(); } ValidateDigit(); do { NextChar(); } while (char.IsDigit(ch)); } if (ch == 'F' || ch == 'f') { NextChar(); } } else { if (textPos != textLen) { throw ParseError(textPos, "Syntax error '{0}'", ch); } id = TokenId.End; } break; } token.id = id; token.text = text.Substring(num, textPos - num); token.pos = num; } private bool TokenIdentifierIs(string id) { if (token.id == TokenId.Identifier) { return string.Equals(id, token.text, StringComparison.OrdinalIgnoreCase); } return false; } private string GetIdentifier() { ValidateToken(TokenId.Identifier, "Identifier expected"); string text = token.text; if (text.Length > 1 && text[0] == '@') { text = text.Substring(1); } return text; } private void ValidateDigit() { if (!char.IsDigit(ch)) { throw ParseError(textPos, "Digit expected"); } } private void ValidateToken(TokenId t, string errorMessage) { if (token.id != t) { throw ParseError(errorMessage); } } private void ValidateToken(TokenId t) { if (token.id != t) { throw ParseError("Syntax error"); } } private Exception ParseError(string format, params object[] args) { return ParseError(token.pos, format, args); } private Exception ParseError(int pos, string format, params object[] args) { return new ParseException(string.Format(CultureInfo.CurrentCulture, format, args), pos); } private static Dictionary CreateKeywords() { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); dictionary.Add("true", trueLiteral); dictionary.Add("false", falseLiteral); dictionary.Add("null", nullLiteral); dictionary.Add(keywordIt, keywordIt); dictionary.Add(keywordIif, keywordIif); dictionary.Add(keywordNew, keywordNew); Type[] array = predefinedTypes; foreach (Type type in array) { dictionary.Add(type.Name, type); } return dictionary; } } internal static class Res { public const string DuplicateIdentifier = "The identifier '{0}' was defined more than once"; public const string ExpressionTypeMismatch = "Expression of type '{0}' expected"; public const string ExpressionExpected = "Expression expected"; public const string InvalidCharacterLiteral = "Character literal must contain exactly one character"; public const string InvalidIntegerLiteral = "Invalid integer literal '{0}'"; public const string InvalidRealLiteral = "Invalid real literal '{0}'"; public const string UnknownIdentifier = "Unknown identifier '{0}'"; public const string NoItInScope = "No 'it' is in scope"; public const string IifRequiresThreeArgs = "The 'iif' function requires three arguments"; public const string FirstExprMustBeBool = "The first expression must be of type 'Boolean'"; public const string BothTypesConvertToOther = "Both of the types '{0}' and '{1}' convert to the other"; public const string NeitherTypeConvertsToOther = "Neither of the types '{0}' and '{1}' converts to the other"; public const string MissingAsClause = "Expression is missing an 'as' clause"; public const string ArgsIncompatibleWithLambda = "Argument list incompatible with lambda expression"; public const string TypeHasNoNullableForm = "Type '{0}' has no nullable form"; public const string NoMatchingConstructor = "No matching constructor in type '{0}'"; public const string AmbiguousConstructorInvocation = "Ambiguous invocation of '{0}' constructor"; public const string CannotConvertValue = "A value of type '{0}' cannot be converted to type '{1}'"; public const string NoApplicableMethod = "No applicable method '{0}' exists in type '{1}'"; public const string MethodsAreInaccessible = "Methods on type '{0}' are not accessible"; public const string MethodIsVoid = "Method '{0}' in type '{1}' does not return a value"; public const string AmbiguousMethodInvocation = "Ambiguous invocation of method '{0}' in type '{1}'"; public const string UnknownPropertyOrField = "No property or field '{0}' exists in type '{1}'"; public const string NoApplicableAggregate = "No applicable aggregate method '{0}' exists"; public const string CannotIndexMultiDimArray = "Indexing of multi-dimensional arrays is not supported"; public const string InvalidIndex = "Array index must be an integer expression"; public const string NoApplicableIndexer = "No applicable indexer exists in type '{0}'"; public const string AmbiguousIndexerInvocation = "Ambiguous invocation of indexer in type '{0}'"; public const string IncompatibleOperand = "Operator '{0}' incompatible with operand type '{1}'"; public const string IncompatibleOperands = "Operator '{0}' incompatible with operand types '{1}' and '{2}'"; public const string UnterminatedStringLiteral = "Unterminated string literal"; public const string InvalidCharacter = "Syntax error '{0}'"; public const string DigitExpected = "Digit expected"; public const string SyntaxError = "Syntax error"; public const string TokenExpected = "{0} expected"; public const string ParseExceptionFormat = "{0} (at index {1})"; public const string ColonExpected = "':' expected"; public const string OpenParenExpected = "'(' expected"; public const string CloseParenOrOperatorExpected = "')' or operator expected"; public const string CloseParenOrCommaExpected = "')' or ',' expected"; public const string DotOrOpenParenExpected = "'.' or '(' expected"; public const string OpenBracketExpected = "'[' expected"; public const string CloseBracketOrCommaExpected = "']' or ',' expected"; public const string IdentifierExpected = "Identifier expected"; } } namespace SimpleJSON { public enum JSONNodeType { Array = 1, Object = 2, String = 3, Number = 4, NullValue = 5, Boolean = 6, None = 7, Custom = 255 } public enum JSONTextMode { Compact, Indent } public abstract class JSONNode { public struct Enumerator { private enum Type { None, Array, Object } private Type type; private Dictionary.Enumerator m_Object; private List.Enumerator m_Array; public bool IsValid => type != Type.None; public KeyValuePair Current { get { if (type == Type.Array) { return new KeyValuePair(string.Empty, m_Array.Current); } if (type == Type.Object) { return m_Object.Current; } return new KeyValuePair(string.Empty, null); } } public Enumerator(List.Enumerator aArrayEnum) { type = Type.Array; m_Object = default(Dictionary.Enumerator); m_Array = aArrayEnum; } public Enumerator(Dictionary.Enumerator aDictEnum) { type = Type.Object; m_Object = aDictEnum; m_Array = default(List.Enumerator); } public bool MoveNext() { if (type == Type.Array) { return m_Array.MoveNext(); } if (type == Type.Object) { return m_Object.MoveNext(); } return false; } } public struct ValueEnumerator { private Enumerator m_Enumerator; public JSONNode Current => m_Enumerator.Current.Value; public ValueEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } public ValueEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } public ValueEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public bool MoveNext() { return m_Enumerator.MoveNext(); } public ValueEnumerator GetEnumerator() { return this; } } public struct KeyEnumerator { private Enumerator m_Enumerator; public JSONNode Current => m_Enumerator.Current.Key; public KeyEnumerator(List.Enumerator aArrayEnum) : this(new Enumerator(aArrayEnum)) { } public KeyEnumerator(Dictionary.Enumerator aDictEnum) : this(new Enumerator(aDictEnum)) { } public KeyEnumerator(Enumerator aEnumerator) { m_Enumerator = aEnumerator; } public bool MoveNext() { return m_Enumerator.MoveNext(); } public KeyEnumerator GetEnumerator() { return this; } } public class LinqEnumerator : IEnumerator>, IDisposable, IEnumerator, IEnumerable>, IEnumerable { private JSONNode m_Node; private Enumerator m_Enumerator; public KeyValuePair Current => m_Enumerator.Current; object IEnumerator.Current => m_Enumerator.Current; internal LinqEnumerator(JSONNode aNode) { m_Node = aNode; if (m_Node != null) { m_Enumerator = m_Node.GetEnumerator(); } } public bool MoveNext() { return m_Enumerator.MoveNext(); } public void Dispose() { m_Node = null; m_Enumerator = default(Enumerator); } public IEnumerator> GetEnumerator() { return new LinqEnumerator(m_Node); } public void Reset() { if (m_Node != null) { m_Enumerator = m_Node.GetEnumerator(); } } IEnumerator IEnumerable.GetEnumerator() { return new LinqEnumerator(m_Node); } } [CompilerGenerated] private sealed class d__39 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private JSONNode <>2__current; private int <>l__initialThreadId; JSONNode IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__39(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { if (<>1__state != 0) { return false; } <>1__state = -1; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; return this; } return new d__39(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__41 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private JSONNode <>2__current; private int <>l__initialThreadId; public JSONNode <>4__this; private IEnumerator <>7__wrap1; private IEnumerator <>7__wrap2; JSONNode IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__41(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || num == 1) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>7__wrap2 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; JSONNode jSONNode = <>4__this; if (num != 0) { if (num != 1) { return false; } <>1__state = -4; goto IL_008d; } <>1__state = -1; <>7__wrap1 = jSONNode.Children.GetEnumerator(); <>1__state = -3; goto IL_00a7; IL_008d: if (<>7__wrap2.MoveNext()) { JSONNode current = <>7__wrap2.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap2 = null; goto IL_00a7; IL_00a7: if (<>7__wrap1.MoveNext()) { JSONNode current2 = <>7__wrap1.Current; <>7__wrap2 = current2.DeepChildren.GetEnumerator(); <>1__state = -4; goto IL_008d; } <>m__Finally1(); <>7__wrap1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } private void <>m__Finally2() { <>1__state = -3; if (<>7__wrap2 != null) { <>7__wrap2.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__41 result; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__41(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } public static bool forceASCII; [ThreadStatic] private static StringBuilder m_EscapeBuilder; public abstract JSONNodeType Tag { get; } public virtual JSONNode this[int aIndex] { get { return null; } set { } } public virtual JSONNode this[string aKey] { get { return null; } set { } } public virtual string Value { get { return ""; } set { } } public virtual int Count => 0; public virtual bool IsNumber => false; public virtual bool IsString => false; public virtual bool IsBoolean => false; public virtual bool IsNull => false; public virtual bool IsArray => false; public virtual bool IsObject => false; public virtual bool Inline { get { return false; } set { } } public virtual IEnumerable Children => new d__39(-2); public IEnumerable DeepChildren => new d__41(-2) { <>4__this = this }; public IEnumerable> Linq => new LinqEnumerator(this); public KeyEnumerator Keys => new KeyEnumerator(GetEnumerator()); public ValueEnumerator Values => new ValueEnumerator(GetEnumerator()); public virtual double AsDouble { get { double result = 0.0; if (double.TryParse(Value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out result)) { return result; } return 0.0; } set { Value = value.ToString(CultureInfo.InvariantCulture); } } public virtual int AsInt { get { return (int)AsDouble; } set { AsDouble = value; } } public virtual float AsFloat { get { return (float)AsDouble; } set { AsDouble = value; } } public virtual bool AsBool { get { bool result = false; if (bool.TryParse(Value, out result)) { return result; } return !string.IsNullOrEmpty(Value); } set { Value = (value ? "true" : "false"); } } public virtual JSONArray AsArray => this as JSONArray; public virtual JSONObject AsObject => this as JSONObject; internal static StringBuilder EscapeBuilder { get { if (m_EscapeBuilder == null) { m_EscapeBuilder = new StringBuilder(); } return m_EscapeBuilder; } } public virtual void Add(string aKey, JSONNode aItem) { } public virtual void Add(JSONNode aItem) { Add("", aItem); } public virtual JSONNode Remove(string aKey) { return null; } public virtual JSONNode Remove(int aIndex) { return null; } public virtual JSONNode Remove(JSONNode aNode) { return aNode; } public override string ToString() { StringBuilder stringBuilder = new StringBuilder(); WriteToStringBuilder(stringBuilder, 0, 0, JSONTextMode.Compact); return stringBuilder.ToString(); } public virtual string ToString(int aIndent) { StringBuilder stringBuilder = new StringBuilder(); WriteToStringBuilder(stringBuilder, 0, aIndent, JSONTextMode.Indent); return stringBuilder.ToString(); } internal abstract void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode); public abstract Enumerator GetEnumerator(); public static implicit operator JSONNode(string s) { return new JSONString(s); } public static implicit operator string(JSONNode d) { if (!(d == null)) { return d.Value; } return null; } public static implicit operator JSONNode(double n) { return new JSONNumber(n); } public static implicit operator double(JSONNode d) { if (!(d == null)) { return d.AsDouble; } return 0.0; } public static implicit operator JSONNode(float n) { return new JSONNumber(n); } public static implicit operator float(JSONNode d) { if (!(d == null)) { return d.AsFloat; } return 0f; } public static implicit operator JSONNode(int n) { return new JSONNumber(n); } public static implicit operator int(JSONNode d) { if (!(d == null)) { return d.AsInt; } return 0; } public static implicit operator JSONNode(bool b) { return new JSONBool(b); } public static implicit operator bool(JSONNode d) { if (!(d == null)) { return d.AsBool; } return false; } public static implicit operator JSONNode(KeyValuePair aKeyValue) { return aKeyValue.Value; } public static bool operator ==(JSONNode a, object b) { if ((object)a == b) { return true; } bool flag = a is JSONNull || (object)a == null || a is JSONLazyCreator; bool flag2 = b is JSONNull || b == null || b is JSONLazyCreator; if (flag && flag2) { return true; } if (!flag) { return a.Equals(b); } return false; } public static bool operator !=(JSONNode a, object b) { return !(a == b); } public override bool Equals(object obj) { return (object)this == obj; } public override int GetHashCode() { return base.GetHashCode(); } internal static string Escape(string aText) { StringBuilder escapeBuilder = EscapeBuilder; escapeBuilder.Length = 0; if (escapeBuilder.Capacity < aText.Length + aText.Length / 10) { escapeBuilder.Capacity = aText.Length + aText.Length / 10; } foreach (char c in aText) { switch (c) { case '\\': escapeBuilder.Append("\\\\"); continue; case '"': escapeBuilder.Append("\\\""); continue; case '\n': escapeBuilder.Append("\\n"); continue; case '\r': escapeBuilder.Append("\\r"); continue; case '\t': escapeBuilder.Append("\\t"); continue; case '\b': escapeBuilder.Append("\\b"); continue; case '\f': escapeBuilder.Append("\\f"); continue; } if (c < ' ' || (forceASCII && c > '\u007f')) { ushort num = c; escapeBuilder.Append("\\u").Append(num.ToString("X4")); } else { escapeBuilder.Append(c); } } string result = escapeBuilder.ToString(); escapeBuilder.Length = 0; return result; } private static void ParseElement(JSONNode ctx, string token, string tokenName, bool quoted) { if (quoted) { ctx.Add(tokenName, token); return; } string text = token.ToLower(); switch (text) { case "false": case "true": ctx.Add(tokenName, text == "true"); return; case "null": ctx.Add(tokenName, null); return; } if (double.TryParse(token, out var result)) { ctx.Add(tokenName, result); } else { ctx.Add(tokenName, token); } } public static JSONNode Parse(string aJSON) { Stack stack = new Stack(); JSONNode jSONNode = null; int i = 0; StringBuilder stringBuilder = new StringBuilder(); string text = ""; bool flag = false; bool flag2 = false; for (; i < aJSON.Length; i++) { switch (aJSON[i]) { case '{': if (flag) { stringBuilder.Append(aJSON[i]); break; } stack.Push(new JSONObject()); if (jSONNode != null) { jSONNode.Add(text, stack.Peek()); } text = ""; stringBuilder.Length = 0; jSONNode = stack.Peek(); break; case '[': if (flag) { stringBuilder.Append(aJSON[i]); break; } stack.Push(new JSONArray()); if (jSONNode != null) { jSONNode.Add(text, stack.Peek()); } text = ""; stringBuilder.Length = 0; jSONNode = stack.Peek(); break; case ']': case '}': if (flag) { stringBuilder.Append(aJSON[i]); break; } if (stack.Count == 0) { throw new Exception("JSON Parse: Too many closing brackets"); } stack.Pop(); if (stringBuilder.Length > 0 || flag2) { ParseElement(jSONNode, stringBuilder.ToString(), text, flag2); flag2 = false; } text = ""; stringBuilder.Length = 0; if (stack.Count > 0) { jSONNode = stack.Peek(); } break; case ':': if (flag) { stringBuilder.Append(aJSON[i]); break; } text = stringBuilder.ToString(); stringBuilder.Length = 0; flag2 = false; break; case '"': flag = !flag; flag2 = flag2 || flag; break; case ',': if (flag) { stringBuilder.Append(aJSON[i]); break; } if (stringBuilder.Length > 0 || flag2) { ParseElement(jSONNode, stringBuilder.ToString(), text, flag2); flag2 = false; } text = ""; stringBuilder.Length = 0; flag2 = false; break; case '\t': case ' ': if (flag) { stringBuilder.Append(aJSON[i]); } break; case '\\': i++; if (flag) { char c = aJSON[i]; switch (c) { case 't': stringBuilder.Append('\t'); break; case 'r': stringBuilder.Append('\r'); break; case 'n': stringBuilder.Append('\n'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'u': { string s = aJSON.Substring(i + 1, 4); stringBuilder.Append((char)int.Parse(s, NumberStyles.AllowHexSpecifier)); i += 4; break; } default: stringBuilder.Append(c); break; } } break; default: stringBuilder.Append(aJSON[i]); break; case '\n': case '\r': break; } } if (flag) { throw new Exception("JSON Parse: Quotation marks seems to be messed up."); } return jSONNode; } } public class JSONArray : JSONNode { [CompilerGenerated] private sealed class d__22 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private JSONNode <>2__current; private int <>l__initialThreadId; public JSONArray <>4__this; private List.Enumerator <>7__wrap1; JSONNode IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__22(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; JSONArray jSONArray = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = jSONArray.m_List.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { JSONNode current = <>7__wrap1.Current; <>2__current = current; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(List.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__22 result; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__22(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private List m_List = new List(); private bool inline; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag => JSONNodeType.Array; public override bool IsArray => true; public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_List.Count) { return new JSONLazyCreator(this); } return m_List[aIndex]; } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (aIndex < 0 || aIndex >= m_List.Count) { m_List.Add(value); } else { m_List[aIndex] = value; } } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this); } set { if (value == null) { value = JSONNull.CreateOrGet(); } m_List.Add(value); } } public override int Count => m_List.Count; public override IEnumerable Children => new d__22(-2) { <>4__this = this }; public override Enumerator GetEnumerator() { return new Enumerator(m_List.GetEnumerator()); } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) { aItem = JSONNull.CreateOrGet(); } m_List.Add(aItem); } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_List.Count) { return null; } JSONNode result = m_List[aIndex]; m_List.RemoveAt(aIndex); return result; } public override JSONNode Remove(JSONNode aNode) { m_List.Remove(aNode); return aNode; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('['); int count = m_List.Count; if (inline) { aMode = JSONTextMode.Compact; } for (int i = 0; i < count; i++) { if (i > 0) { aSB.Append(','); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine(); } if (aMode == JSONTextMode.Indent) { aSB.Append(' ', aIndent + aIndentInc); } m_List[i].WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine().Append(' ', aIndent); } aSB.Append(']'); } } public class JSONObject : JSONNode { [CompilerGenerated] private sealed class d__23 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private JSONNode <>2__current; private int <>l__initialThreadId; public JSONObject <>4__this; private Dictionary.Enumerator <>7__wrap1; JSONNode IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__23(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = default(Dictionary.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; JSONObject jSONObject = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>7__wrap1 = jSONObject.m_Dict.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; break; } if (<>7__wrap1.MoveNext()) { <>2__current = <>7__wrap1.Current.Value; <>1__state = 1; return true; } <>m__Finally1(); <>7__wrap1 = default(Dictionary.Enumerator); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap1).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__23 result; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; result = this; } else { result = new d__23(0) { <>4__this = <>4__this }; } return result; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private Dictionary m_Dict = new Dictionary(); private bool inline; public override bool Inline { get { return inline; } set { inline = value; } } public override JSONNodeType Tag => JSONNodeType.Object; public override bool IsObject => true; public override JSONNode this[string aKey] { get { if (m_Dict.ContainsKey(aKey)) { return m_Dict[aKey]; } return new JSONLazyCreator(this, aKey); } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (m_Dict.ContainsKey(aKey)) { m_Dict[aKey] = value; } else { m_Dict.Add(aKey, value); } } } public override JSONNode this[int aIndex] { get { if (aIndex < 0 || aIndex >= m_Dict.Count) { return null; } return m_Dict.ElementAt(aIndex).Value; } set { if (value == null) { value = JSONNull.CreateOrGet(); } if (aIndex >= 0 && aIndex < m_Dict.Count) { string key = m_Dict.ElementAt(aIndex).Key; m_Dict[key] = value; } } } public override int Count => m_Dict.Count; public override IEnumerable Children => new d__23(-2) { <>4__this = this }; public override Enumerator GetEnumerator() { return new Enumerator(m_Dict.GetEnumerator()); } public override void Add(string aKey, JSONNode aItem) { if (aItem == null) { aItem = JSONNull.CreateOrGet(); } if (!string.IsNullOrEmpty(aKey)) { if (m_Dict.ContainsKey(aKey)) { m_Dict[aKey] = aItem; } else { m_Dict.Add(aKey, aItem); } } else { m_Dict.Add(Guid.NewGuid().ToString(), aItem); } } public override JSONNode Remove(string aKey) { if (!m_Dict.ContainsKey(aKey)) { return null; } JSONNode result = m_Dict[aKey]; m_Dict.Remove(aKey); return result; } public override JSONNode Remove(int aIndex) { if (aIndex < 0 || aIndex >= m_Dict.Count) { return null; } KeyValuePair keyValuePair = m_Dict.ElementAt(aIndex); m_Dict.Remove(keyValuePair.Key); return keyValuePair.Value; } public override JSONNode Remove(JSONNode aNode) { try { KeyValuePair keyValuePair = m_Dict.Where((KeyValuePair k) => k.Value == aNode).First(); m_Dict.Remove(keyValuePair.Key); return aNode; } catch { return null; } } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('{'); bool flag = true; if (inline) { aMode = JSONTextMode.Compact; } foreach (KeyValuePair item in m_Dict) { if (!flag) { aSB.Append(','); } flag = false; if (aMode == JSONTextMode.Indent) { aSB.AppendLine(); } if (aMode == JSONTextMode.Indent) { aSB.Append(' ', aIndent + aIndentInc); } aSB.Append('"').Append(JSONNode.Escape(item.Key)).Append('"'); if (aMode == JSONTextMode.Compact) { aSB.Append(':'); } else { aSB.Append(" : "); } item.Value.WriteToStringBuilder(aSB, aIndent + aIndentInc, aIndentInc, aMode); } if (aMode == JSONTextMode.Indent) { aSB.AppendLine().Append(' ', aIndent); } aSB.Append('}'); } } public class JSONString : JSONNode { private string m_Data; public override JSONNodeType Tag => JSONNodeType.String; public override bool IsString => true; public override string Value { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONString(string aData) { m_Data = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append('"').Append(JSONNode.Escape(m_Data)).Append('"'); } public override bool Equals(object obj) { if (base.Equals(obj)) { return true; } if (obj is string text) { return m_Data == text; } JSONString jSONString = obj as JSONString; if (jSONString != null) { return m_Data == jSONString.m_Data; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONNumber : JSONNode { private double m_Data; public override JSONNodeType Tag => JSONNodeType.Number; public override bool IsNumber => true; public override string Value { get { return m_Data.ToString(CultureInfo.InvariantCulture); } set { if (double.TryParse(value, NumberStyles.Float | NumberStyles.AllowThousands, CultureInfo.InvariantCulture, out var result)) { m_Data = result; } } } public override double AsDouble { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONNumber(double aData) { m_Data = aData; } public JSONNumber(string aData) { Value = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append(m_Data); } private static bool IsNumeric(object value) { if (!(value is int) && !(value is uint) && !(value is float) && !(value is double) && !(value is decimal) && !(value is long) && !(value is ulong) && !(value is short) && !(value is ushort) && !(value is sbyte)) { return value is byte; } return true; } public override bool Equals(object obj) { if (obj == null) { return false; } if (base.Equals(obj)) { return true; } JSONNumber jSONNumber = obj as JSONNumber; if (jSONNumber != null) { return m_Data == jSONNumber.m_Data; } if (IsNumeric(obj)) { return Convert.ToDouble(obj) == m_Data; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONBool : JSONNode { private bool m_Data; public override JSONNodeType Tag => JSONNodeType.Boolean; public override bool IsBoolean => true; public override string Value { get { return m_Data.ToString(); } set { if (bool.TryParse(value, out var result)) { m_Data = result; } } } public override bool AsBool { get { return m_Data; } set { m_Data = value; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONBool(bool aData) { m_Data = aData; } public JSONBool(string aData) { Value = aData; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append(m_Data ? "true" : "false"); } public override bool Equals(object obj) { if (obj == null) { return false; } if (obj is bool) { return m_Data == (bool)obj; } return false; } public override int GetHashCode() { return m_Data.GetHashCode(); } } public class JSONNull : JSONNode { private static JSONNull m_StaticInstance = new JSONNull(); public static bool reuseSameInstance = true; public override JSONNodeType Tag => JSONNodeType.NullValue; public override bool IsNull => true; public override string Value { get { return "null"; } set { } } public override bool AsBool { get { return false; } set { } } public static JSONNull CreateOrGet() { if (reuseSameInstance) { return m_StaticInstance; } return new JSONNull(); } private JSONNull() { } public override Enumerator GetEnumerator() { return default(Enumerator); } public override bool Equals(object obj) { if ((object)this == obj) { return true; } return obj is JSONNull; } public override int GetHashCode() { return 0; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } internal class JSONLazyCreator : JSONNode { private JSONNode m_Node; private string m_Key; public override JSONNodeType Tag => JSONNodeType.None; public override JSONNode this[int aIndex] { get { return new JSONLazyCreator(this); } set { JSONArray jSONArray = new JSONArray(); jSONArray.Add(value); Set(jSONArray); } } public override JSONNode this[string aKey] { get { return new JSONLazyCreator(this, aKey); } set { JSONObject jSONObject = new JSONObject(); jSONObject.Add(aKey, value); Set(jSONObject); } } public override int AsInt { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override float AsFloat { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0f; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override double AsDouble { get { JSONNumber aVal = new JSONNumber(0.0); Set(aVal); return 0.0; } set { JSONNumber aVal = new JSONNumber(value); Set(aVal); } } public override bool AsBool { get { JSONBool aVal = new JSONBool(aData: false); Set(aVal); return false; } set { JSONBool aVal = new JSONBool(value); Set(aVal); } } public override JSONArray AsArray { get { JSONArray jSONArray = new JSONArray(); Set(jSONArray); return jSONArray; } } public override JSONObject AsObject { get { JSONObject jSONObject = new JSONObject(); Set(jSONObject); return jSONObject; } } public override Enumerator GetEnumerator() { return default(Enumerator); } public JSONLazyCreator(JSONNode aNode) { m_Node = aNode; m_Key = null; } public JSONLazyCreator(JSONNode aNode, string aKey) { m_Node = aNode; m_Key = aKey; } private void Set(JSONNode aVal) { if (m_Key == null) { m_Node.Add(aVal); } else { m_Node.Add(m_Key, aVal); } m_Node = null; } public override void Add(JSONNode aItem) { JSONArray jSONArray = new JSONArray(); jSONArray.Add(aItem); Set(jSONArray); } public override void Add(string aKey, JSONNode aItem) { JSONObject jSONObject = new JSONObject(); jSONObject.Add(aKey, aItem); Set(jSONObject); } public static bool operator ==(JSONLazyCreator a, object b) { if (b == null) { return true; } return (object)a == b; } public static bool operator !=(JSONLazyCreator a, object b) { return !(a == b); } public override bool Equals(object obj) { if (obj == null) { return true; } return (object)this == obj; } public override int GetHashCode() { return 0; } internal override void WriteToStringBuilder(StringBuilder aSB, int aIndent, int aIndentInc, JSONTextMode aMode) { aSB.Append("null"); } } public static class JSON { public static JSONNode Parse(string aJSON) { return JSONNode.Parse(aJSON); } } } namespace XUnity.AutoTranslator.Plugin { internal class SceneLoadInformation { public SceneInformation ActiveScene { get; set; } public List LoadedScenes { get; set; } public SceneLoadInformation() { LoadedScenes = new List(); if (UnityFeatures.SupportsSceneManager) { LoadBySceneManager(); } else { LoadByApplication(); } } public void LoadBySceneManager() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); ActiveScene = new SceneInformation(((Scene)(ref activeScene)).buildIndex, ((Scene)(ref activeScene)).name); for (int i = 0; i < SceneManager.sceneCount; i++) { Scene sceneAt = SceneManager.GetSceneAt(i); LoadedScenes.Add(new SceneInformation(((Scene)(ref sceneAt)).buildIndex, ((Scene)(ref sceneAt)).name)); } } public void LoadByApplication() { ActiveScene = new SceneInformation(Application.loadedLevel, Application.loadedLevelName); LoadedScenes.Add(new SceneInformation(Application.loadedLevel, Application.loadedLevelName)); } } internal class SceneInformation { public int Id { get; set; } public string Name { get; set; } public SceneInformation(int id, string name) { Id = id; Name = name; } } } namespace XUnity.AutoTranslator.Plugin.Utilities { internal static class TranslationScopeHelper { public static int GetScope(object ui) { if (Settings.EnableTranslationScoping) { try { int num = -1; Component val = (Component)((ui is Component) ? ui : null); if (val != null && Object.op_Implicit((Object)(object)val)) { num = GetScopeFromComponent(val); } if (num != -1) { return num; } if (ui is GUIContent) { return -1; } return GetActiveSceneId(); } catch (MissingMemberException ex) { XuaLogger.AutoTranslator.Error((Exception)ex, "A 'missing member' error occurred while retriving translation scope. Disabling translation scopes."); Settings.EnableTranslationScoping = false; } } return -1; } private static int GetScopeFromComponent(Component component) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) Scene scene = component.gameObject.scene; return ((Scene)(ref scene)).buildIndex; } public static int GetActiveSceneId() { if (UnityFeatures.SupportsSceneManager) { return GetActiveSceneIdBySceneManager(); } return GetActiveSceneIdByApplication(); } private static int GetActiveSceneIdBySceneManager() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) Scene activeScene = SceneManager.GetActiveScene(); return ((Scene)(ref activeScene)).buildIndex; } public static void RegisterSceneLoadCallback(Action sceneLoaded) { SceneManagerLoader.EnableSceneLoadScanInternal(sceneLoaded); } private static int GetActiveSceneIdByApplication() { return Application.loadedLevel; } } internal static class SceneManagerLoader { public static void EnableSceneLoadScanInternal(Action sceneLoaded) { SceneManager.sceneLoaded += delegate(Scene arg1, LoadSceneMode arg2) { sceneLoaded(((Scene)(ref arg1)).buildIndex); }; } } internal static class TranslationScopes { public const int None = -1; } } namespace XUnity.AutoTranslator.Plugin.Core { public class AutoTranslationPlugin : MonoBehaviour, IMonoBehaviour, IMonoBehaviour_Update, IInternalTranslator, ITranslator, ITranslationRegistry { [CompilerGenerated] private sealed class d__124 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private GameObject <>2__current; private int <>l__initialThreadId; private GameObject[] <>7__wrap1; private int <>7__wrap2; GameObject IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__124(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; goto IL_0073; } <>1__state = -1; GameObject[] array = ComponentHelper.FindObjectsOfType(); <>7__wrap1 = array; <>7__wrap2 = 0; goto IL_0081; IL_0073: <>7__wrap2++; goto IL_0081; IL_0081: if (<>7__wrap2 < <>7__wrap1.Length) { GameObject val = <>7__wrap1[<>7__wrap2]; if ((Object)(object)val.transform != (Object)null && (Object)(object)val.transform.parent == (Object)null) { <>2__current = val; <>1__state = 1; return true; } goto IL_0073; } <>7__wrap1 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; return this; } return new d__124(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__103 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public AutoTranslationPlugin <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__103(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; AutoTranslationPlugin autoTranslationPlugin = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: { <>1__state = -1; if (autoTranslationPlugin.PluginTextCaches.Count == 0) { XuaLogger.AutoTranslator.Info("Skipping plugin scan because no plugin-specific translations has been registered."); return false; } XuaLogger.AutoTranslator.Info("Scanning for plugins to hook for translations..."); string value = StringExtensions.UseCorrectDirectorySeparators(Application.dataPath); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { if (!assembly.FullName.StartsWith("XUnity") && !assembly.ManifestModule.GetType().FullName.Contains("Emit") && !StringExtensions.UseCorrectDirectorySeparators(assembly.Location).StartsWith(value, StringComparison.OrdinalIgnoreCase) && autoTranslationPlugin.PluginTextCaches.TryGetValue(assembly.GetName().Name, out var _)) { HooksSetup.InstallIMGUIBasedPluginTranslationHooks(assembly, final: false); } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while scanning assembly: " + assembly.FullName); } } return false; } } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__96 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public object ui; public TextTranslationInfo info; public float delay; public Action onTextStabilized; public int currentTries; public int maxTries; public Action onMaxTriesExceeded; private bool 5__2; private string 5__3; private float 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__96(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__3 = null; <>1__state = -2; } private bool MoveNext() { object obj; float realtimeSinceStartup; string text; switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>2__current = null; <>1__state = 1; return true; case 1: <>1__state = -1; 5__2 = false; goto IL_0110; case 2: <>1__state = -1; goto IL_00c2; case 3: { <>1__state = -1; goto IL_00b5; } IL_0110: if (currentTries >= maxTries) { break; } 5__3 = ui.GetText(info); obj = CoroutineHelper.CreateWaitForSecondsRealtime(delay); if (obj != null) { <>2__current = obj; <>1__state = 2; return true; } realtimeSinceStartup = Time.realtimeSinceStartup; 5__4 = realtimeSinceStartup + delay; goto IL_00b5; IL_00c2: text = ui.GetText(info); if (5__3 == text) { onTextStabilized(text); 5__2 = true; break; } currentTries++; 5__3 = null; goto IL_0110; IL_00b5: if (Time.realtimeSinceStartup < 5__4) { <>2__current = null; <>1__state = 3; return true; } goto IL_00c2; } if (!5__2) { onMaxTriesExceeded(); } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__97 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public UntranslatedText textKey; public AutoTranslationPlugin <>4__this; public float delay; public Action onTextStabilized; public Action onFailed; private string 5__2; private float 5__3; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__97(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } 5__2 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; AutoTranslationPlugin autoTranslationPlugin = <>4__this; bool flag; switch (num) { default: return false; case 0: { <>1__state = -1; 5__2 = textKey.TemplatedOriginal_Text_FullyTrimmed; if (autoTranslationPlugin._immediatelyTranslating.Contains(5__2)) { break; } autoTranslationPlugin._immediatelyTranslating.Add(5__2); <>1__state = -3; object obj = CoroutineHelper.CreateWaitForSecondsRealtime(delay); if (obj != null) { <>2__current = obj; <>1__state = 1; return true; } float realtimeSinceStartup = Time.realtimeSinceStartup; 5__3 = realtimeSinceStartup + delay; goto IL_00d2; } case 1: <>1__state = -3; goto IL_00df; case 2: { <>1__state = -3; goto IL_00d2; } IL_00d2: if (Time.realtimeSinceStartup < 5__3) { <>2__current = null; <>1__state = 2; return true; } goto IL_00df; IL_00df: flag = true; foreach (string item in autoTranslationPlugin._immediatelyTranslating) { if (5__2 != item && StringExtensions.RemindsOf(5__2, item)) { flag = false; break; } } if (flag) { onTextStabilized(); } else { onFailed?.Invoke(); } <>m__Finally1(); break; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; <>4__this._immediatelyTranslating.Remove(5__2); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } internal static AutoTranslationPlugin Current; private bool _hasResizedCurrentComponentDuringDiscovery; internal XuaWindow MainWindow; internal TranslationAggregatorWindow TranslationAggregatorWindow; internal TranslationAggregatorOptionsWindow TranslationAggregatorOptionsWindow; internal TranslationManager TranslationManager; internal TextTranslationCache TextCache; internal Dictionary PluginTextCaches = new Dictionary(StringComparer.OrdinalIgnoreCase); internal TextureTranslationCache TextureCache; internal UIResizeCache ResizeCache; internal SpamChecker SpamChecker; internal static RegexOptions RegexCompiledSupportedFlag = RegexOptions.None; private Dictionary CachedKeys = new Dictionary(StringComparer.Ordinal); private List> _shouldIgnore = new List>(); private List _textsToCopyToClipboardOrdered = new List(); private HashSet _textsToCopyToClipboard = new HashSet(); private float _clipboardUpdated; private HashSet _immediatelyTranslating = new HashSet(); private bool _isInTranslatedMode = true; private bool _textHooksEnabled = true; private float _batchOperationSecondCounter; private bool _hasValidOverrideFont; private bool _hasOverridenFont; private bool _initialized; private bool _started; private bool _temporarilyDisabled; private string _requireSpriteRendererCheckCausedBy; private int _lastSpriteUpdateFrame = -1; private bool _isCalledFromSceneManager; private bool _translationReloadRequest; private bool _hasUiBeenSetup; private static bool _inputSupported = true; public void Initialize() { Current = this; Paths.Initialize(); HarmonyLoader.Load(); Settings.Configure(); DebugConsole.Enable(); InitializeHarmonyDetourBridge(); CheckRegexCompiledSupport(); InitializeTextTranslationCaches(); HooksSetup.InstallTextHooks(); HooksSetup.InstallImageHooks(); HooksSetup.InstallSpriteRendererHooks(); HooksSetup.InstallTextGetterCompatHooks(); HooksSetup.InstallComponentBasedPluginTranslationHooks(); TextureCache = new TextureTranslationCache(); TextureCache.TextureTranslationFileChanged += TextureCache_TextureTranslationFileChanged; ResizeCache = new UIResizeCache(); TranslationManager = new TranslationManager(); TranslationManager.JobCompleted += OnJobCompleted; TranslationManager.JobFailed += OnJobFailed; TranslationManager.InitializeEndpoints(); SpamChecker = new SpamChecker(TranslationManager); UnityTextParsers.Initialize(); InitializeResourceRedirector(); ValidateConfiguration(); EnableSceneLoadScan(); LoadFallbackFont(); LoadTranslations(reload: false); XuaLogger.AutoTranslator.Info("Loaded XUnity.AutoTranslator into Unity [" + Application.unityVersion + "] game."); AutoTranslatorState.OnPluginInitializationCompleted(); } private void CheckRegexCompiledSupport() { try { string input = "She believed"; if (new Regex(".he ..lie..d", RegexOptions.Compiled).Match(input).Success) { RegexCompiledSupportedFlag = RegexOptions.Compiled; } else { XuaLogger.AutoTranslator.Info("Unknown Error at CheckRegexCompiledSupport"); } } catch (Exception) { XuaLogger.AutoTranslator.Info("The current version of the game doesn't support compiled Regex"); } } private static void LoadFallbackFont() { try { if (!string.IsNullOrEmpty(Settings.FallbackFontTextMeshPro)) { Object orCreateFallbackFontTextMeshPro = FontCache.GetOrCreateFallbackFontTextMeshPro(); if (TMP_Settings_Properties.FallbackFontAssets == null) { XuaLogger.AutoTranslator.Info("Cannot use fallback font because it is not supported in this version."); return; } if (orCreateFallbackFontTextMeshPro == (Object)null) { XuaLogger.AutoTranslator.Warn("Could not load fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro); return; } ((IList)TMP_Settings_Properties.FallbackFontAssets.Get((object)null)).Add(orCreateFallbackFontTextMeshPro); XuaLogger.AutoTranslator.Info("Loaded fallback font for TextMesh Pro: " + Settings.FallbackFontTextMeshPro); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to load fallback font for TextMesh Pro."); } } private static void InitializeHarmonyDetourBridge() { try { if (Settings.InitializeHarmonyDetourBridge) { InitializeHarmonyDetourBridgeSafe(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing harmony detour bridge."); } } private static void InitializeHarmonyDetourBridgeSafe() { HarmonyDetourBridge.Init(true, (Type)0); } private void InitializeTextTranslationCaches() { try { TextCache = new TextTranslationCache(); TextCache.TextTranslationFileChanged += TextCache_TextTranslationFileChanged; DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Settings.TranslationsPath, "plugins")); if (directoryInfo.Exists) { DirectoryInfo[] directories = directoryInfo.GetDirectories(); foreach (DirectoryInfo directoryInfo2 in directories) { TextTranslationCache value = new TextTranslationCache(directoryInfo2); PluginTextCaches.Add(directoryInfo2.Name, value); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing text translation caches."); } } private void TextCache_TextTranslationFileChanged() { _translationReloadRequest = true; } private void TextureCache_TextureTranslationFileChanged() { _translationReloadRequest = true; } private static void EnableLogAllLoadedResources() { ResourceRedirection.LogAllLoadedResources = true; } private void EnableTextAssetLoadedHandler() { new TextAssetLoadedHandler(); } private void InitializeResourceRedirector() { try { if (Settings.LogAllLoadedResources) { EnableLogAllLoadedResources(); } if (Settings.EnableTextAssetRedirector) { EnableTextAssetLoadedHandler(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing resource redirectors."); } } private void InitializeGUI() { DisableAutoTranslator(); try { if (!_hasUiBeenSetup) { _hasUiBeenSetup = true; MainWindow = new XuaWindow(CreateXuaViewModel()); TranslationAggregatorViewModel viewModel = CreateTranslationAggregatorViewModel(); TranslationAggregatorWindow = new TranslationAggregatorWindow(viewModel); TranslationAggregatorOptionsWindow = new TranslationAggregatorOptionsWindow(viewModel); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up UI."); } finally { EnableAutoTranslator(); } } private TranslationAggregatorViewModel CreateTranslationAggregatorViewModel() { return new TranslationAggregatorViewModel(TranslationManager); } private XuaViewModel CreateXuaViewModel() { return new XuaViewModel(new List { new ToggleViewModel(" Translated", "TRANSLATED\nThe plugin currently displays translated texts. Disabling this does not mean the plugin will no longer perform translations, just that they will not be displayed.", "NOT TRANSLATED\nThe plugin currently displays untranslated texts.", ToggleTranslation, () => _isInTranslatedMode), new ToggleViewModel(" Silent Logging", "SILENT\nThe plugin will not print out success messages to the log in relation to translations.", "VERBOSE\nThe plugin will print out success messages to the log in relation to translations.", ToggleSilentMode, () => Settings.EnableSilentMode), new ToggleViewModel(" Translation Aggregator", "SHOWN\nThe translation aggregator window is shown.", "HIDDEN\nThe translation aggregator window is not shown.", ToggleTranslationAggregator, () => TranslationAggregatorWindow != null && TranslationAggregatorWindow.IsShown) }, new DropdownViewModel("----", "SELECT TRANSLATOR\nNo translator is currently selected, which means no new translations will be performed. Please select one from the dropdown.", "----", "UNSELECT TRANSLATOR\nThis will unselect the current translator, which means no new translations will be performed.", TranslationManager.AllEndpoints.Select((TranslationEndpointManager x) => new TranslatorDropdownOptionViewModel(fallback: false, () => x == TranslationManager.CurrentEndpoint, x)).ToList(), OnEndpointSelected), new DropdownViewModel("----", "SELECT FALLBACK TRANSLATOR\nNo fallback translator is currently selected, which means if the primary translator fails no translation will be provided for the failing text. Please select one from the dropdown.", "----", "UNSELECT FALLBACK TRANSLATOR\nThis will unselect the current fallback translator.", TranslationManager.AllEndpoints.Select((TranslationEndpointManager x) => new TranslatorDropdownOptionViewModel(fallback: true, () => x == TranslationManager.FallbackEndpoint, x)).ToList(), OnFallbackEndpointSelected), new List { new ButtonViewModel("Reboot", "REBOOT PLUGIN\nReboots the plugin if it has been shutdown. This only works if the plugin was shut down due to consequtive errors towards the translation endpoint.", RebootPlugin, null), new ButtonViewModel("Reload", "RELOAD TRANSLATION\nReloads all translation text files and texture files from disk.", ReloadTranslations, null), new ButtonViewModel("Hook", "MANUAL HOOK\nTraverses the unity object tree for looking for anything that can be translated. Performs a translation if something is found.", ManualHook, null) }, new List { new LabelViewModel("Version: ", () => "5.6.1"), new LabelViewModel("Plugin status: ", () => (!Settings.IsShutdown) ? "Running" : "Shutdown"), new LabelViewModel("Translator status: ", GetCurrentEndpointStatus), new LabelViewModel("Running translations: ", () => $"{TranslationManager.OngoingTranslations}"), new LabelViewModel("Served translations: ", () => $"{Settings.TranslationCount} / {Settings.MaxTranslationsBeforeShutdown}"), new LabelViewModel("Queued translations: ", () => $"{TranslationManager.UnstartedTranslations} / {Settings.MaxUnstartedJobs}"), new LabelViewModel("Error'ed translations: ", () => $"{TranslationManager.CurrentEndpoint?.ConsecutiveErrors ?? 0} / {Settings.MaxErrors}") }); } private void ToggleTranslationAggregator() { if (TranslationAggregatorWindow != null) { TranslationAggregatorWindow.IsShown = !TranslationAggregatorWindow.IsShown; } } private void ToggleSilentMode() { Settings.SetSlientMode(!Settings.EnableSilentMode); } private string GetCurrentEndpointStatus() { TranslationEndpointManager currentEndpoint = TranslationManager.CurrentEndpoint; if (currentEndpoint == null) { return "Not selected"; } if (currentEndpoint.HasFailedDueToConsecutiveErrors) { return "Shutdown"; } return "Running"; } private void ValidateConfiguration() { try { if (!string.IsNullOrEmpty(Settings.OverrideFont)) { string[] supportedFonts = GetSupportedFonts(); if (supportedFonts == null) { XuaLogger.AutoTranslator.Warn("Unable to validate OverrideFont validity due to shimmed APIs."); } else if (!supportedFonts.Contains(Settings.OverrideFont)) { XuaLogger.AutoTranslator.Error("The specified override font is not available. Available fonts: " + string.Join(", ", supportedFonts)); Settings.OverrideFont = null; } else { _hasValidOverrideFont = true; } } if (!string.IsNullOrEmpty(Settings.OverrideFontTextMeshPro)) { _hasValidOverrideFont = true; } _hasOverridenFont = _hasValidOverrideFont; } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while checking supported fonts."); } } internal static string[] GetSupportedFonts() { try { return FontHelper.GetOSInstalledFontNames(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "Unable to retrieve OS installed fonts."); return null; } } private void OnEndpointSelected(TranslationEndpointManager endpoint) { if (TranslationManager.CurrentEndpoint == endpoint) { return; } TranslationManager.CurrentEndpoint = endpoint; if (TranslationManager.CurrentEndpoint != null) { if (!Settings.IsShutdown) { if (TranslationManager.CurrentEndpoint.HasFailedDueToConsecutiveErrors) { RebootPlugin(); } ManualHook(); } if (TranslationManager.CurrentEndpoint == TranslationManager.FallbackEndpoint) { XuaLogger.AutoTranslator.Warn("Cannot use same fallback endpoint as primary."); } } Settings.SetEndpoint(TranslationManager.CurrentEndpoint?.Endpoint.Id); XuaLogger.AutoTranslator.Info("Set translator endpoint to '" + TranslationManager.CurrentEndpoint?.Endpoint.Id + "'."); } private void OnFallbackEndpointSelected(TranslationEndpointManager endpoint) { if (TranslationManager.FallbackEndpoint != endpoint) { TranslationManager.FallbackEndpoint = endpoint; Settings.SetFallback(TranslationManager.FallbackEndpoint?.Endpoint.Id); XuaLogger.AutoTranslator.Info("Set fallback endpoint to '" + TranslationManager.FallbackEndpoint?.Endpoint.Id + "'."); if (TranslationManager.CurrentEndpoint != null && TranslationManager.CurrentEndpoint == TranslationManager.FallbackEndpoint) { XuaLogger.AutoTranslator.Warn("Cannot use same fallback endpoint as primary."); } } } private void EnableSceneLoadScan() { try { XuaLogger.AutoTranslator.Debug("Probing whether OnLevelWasLoaded or SceneManager is supported in this version of Unity. Any warnings related to OnLevelWasLoaded coming from Unity can safely be ignored."); if (UnityFeatures.SupportsSceneManager) { TranslationScopeHelper.RegisterSceneLoadCallback(OnLevelWasLoadedFromSceneManager); XuaLogger.AutoTranslator.Debug("SceneManager is supported in this version of Unity."); } else { XuaLogger.AutoTranslator.Debug("SceneManager is not supported in this version of Unity. Falling back to OnLevelWasLoaded and Application level API."); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while settings up scene-load scans."); } } internal void OnLevelWasLoadedFromSceneManager(int id) { try { _isCalledFromSceneManager = true; OnLevelWasLoaded(id); } finally { _isCalledFromSceneManager = false; } } private void OnLevelWasLoaded(int id) { if ((!UnityFeatures.SupportsSceneManager || (UnityFeatures.SupportsSceneManager && _isCalledFromSceneManager)) && Settings.EnableTextureScanOnSceneLoad && (Settings.EnableTextureDumping || Settings.EnableTextureTranslation)) { XuaLogger.AutoTranslator.Info("Performing texture lookup during scene load..."); float realtimeSinceStartup = Time.realtimeSinceStartup; ManualHookForTextures(); float realtimeSinceStartup2 = Time.realtimeSinceStartup; XuaLogger.AutoTranslator.Info($"Finished texture lookup (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); } } private void LoadTranslations(bool reload) { ResizeCache.LoadResizeCommandsInFiles(); SettingsTranslationsInitializer.LoadTranslations(); TextCache.LoadTranslationFiles(); if (reload) { Dictionary dictionary = new Dictionary(StringComparer.OrdinalIgnoreCase); DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(Settings.TranslationsPath, "plugins")); if (directoryInfo.Exists) { DirectoryInfo[] directories = directoryInfo.GetDirectories(); foreach (DirectoryInfo directoryInfo2 in directories) { dictionary.Add(directoryInfo2.Name, directoryInfo2); } } foreach (KeyValuePair pluginTextCache in PluginTextCaches) { pluginTextCache.Value.LoadTranslationFiles(); dictionary.Remove(pluginTextCache.Key); } foreach (KeyValuePair item in dictionary) { string assemblyName = item.Value.Name; TextTranslationCache textTranslationCache = new TextTranslationCache(item.Value); PluginTextCaches.Add(assemblyName, textTranslationCache); textTranslationCache.LoadTranslationFiles(); Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly x) => x.GetName().Name.Equals(assemblyName, StringComparison.OrdinalIgnoreCase)); if ((object)assembly != null) { HooksSetup.InstallIMGUIBasedPluginTranslationHooks(assembly, final: true); } } HooksSetup.InstallComponentBasedPluginTranslationHooks(); } else { foreach (KeyValuePair pluginTextCache2 in PluginTextCaches) { pluginTextCache2.Value.LoadTranslationFiles(); } } TextureCache.LoadTranslationFiles(); } private void CreateTranslationJobFor(TranslationEndpointManager endpoint, object ui, UntranslatedText key, InternalTranslationResult translationResult, ParserTranslationContext context, bool checkOtherEndpoints, bool checkSpam, bool saveResultGlobally, bool isTranslatable, bool allowFallback, UntranslatedTextInfo untranslatedTextContext) { if (endpoint.EnqueueTranslation(ui, key, translationResult, context, untranslatedTextContext, checkOtherEndpoints, saveResultGlobally, isTranslatable, allowFallback) != null && isTranslatable && checkSpam && !(endpoint.Endpoint is PassthroughTranslateEndpoint)) { SpamChecker.PerformChecks(key.TemplatedOriginal_Text_FullyTrimmed, endpoint); } } private void IncrementBatchOperations() { _batchOperationSecondCounter += Time.deltaTime; if (!(_batchOperationSecondCounter > Settings.IncreaseBatchOperationsEvery)) { return; } foreach (TranslationEndpointManager configuredEndpoint in TranslationManager.ConfiguredEndpoints) { if (configuredEndpoint.AvailableBatchOperations < Settings.MaxAvailableBatchOperations) { configuredEndpoint.AvailableBatchOperations++; } } _batchOperationSecondCounter = 0f; } private void UpdateSpriteRenderers() { if (!Settings.EnableSpriteRendererHooking || (!Settings.EnableTextureTranslation && !Settings.EnableTextureDumping) || _requireSpriteRendererCheckCausedBy == null) { return; } try { float realtimeSinceStartup = Time.realtimeSinceStartup; SpriteRenderer[] array = ComponentHelper.FindObjectsOfType(); foreach (SpriteRenderer source in array) { Texture2D texture = null; Hook_ImageChangedOnComponent(source, ref texture, isPrefixHooked: false, onEnable: false); } double num = Math.Round(Time.realtimeSinceStartup - realtimeSinceStartup, 2); XuaLogger.AutoTranslator.Debug("Update SpriteRenderers caused by " + _requireSpriteRendererCheckCausedBy + " component (took " + num + " seconds)"); } finally { _requireSpriteRendererCheckCausedBy = null; } } private void QueueNewUntranslatedForClipboard(string untranslatedText) { if (Settings.CopyToClipboard && UnityFeatures.SupportsClipboard && !_textsToCopyToClipboard.Contains(untranslatedText)) { _textsToCopyToClipboard.Add(untranslatedText); _textsToCopyToClipboardOrdered.Add(untranslatedText); _clipboardUpdated = Time.realtimeSinceStartup; } } internal string Hook_TextChanged_WithResult(object ui, string text, bool onEnable) { try { string result = null; if (_textHooksEnabled && !_temporarilyDisabled) { try { TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo(); bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo); if (onEnable && orCreateTextTranslationInfo != null && CallOrigin.TextCache != null) { orCreateTextTranslationInfo.TextCache = CallOrigin.TextCache; } CallOrigin.ExpectsTextToBeReturned = true; result = TranslateOrQueueWebJob(ui, text, ignoreComponentState, orCreateTextTranslationInfo); } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An unexpected error occurred."); } finally { _hasResizedCurrentComponentDuringDiscovery = false; } } if (onEnable) { CheckSpriteRenderer(ui); } return result; } finally { CallOrigin.ExpectsTextToBeReturned = false; } } internal void Hook_TextChanged(object ui, bool onEnable) { if (_textHooksEnabled && !_temporarilyDisabled) { try { TextTranslationInfo orCreateTextTranslationInfo = ui.GetOrCreateTextTranslationInfo(); bool ignoreComponentState = DiscoverComponent(ui, orCreateTextTranslationInfo); if (onEnable && orCreateTextTranslationInfo != null && CallOrigin.TextCache != null) { orCreateTextTranslationInfo.TextCache = CallOrigin.TextCache; } TranslateOrQueueWebJob(ui, null, ignoreComponentState, orCreateTextTranslationInfo); } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An unexpected error occurred."); } finally { _hasResizedCurrentComponentDuringDiscovery = false; } } if (onEnable) { CheckSpriteRenderer(ui); } } internal void Hook_ImageChangedOnComponent(object source, ref Texture2D texture, bool isPrefixHooked, bool onEnable) { if (CallOrigin.ImageHooksEnabled && source.IsKnownImageType()) { Sprite sprite = null; HandleImage(source, ref sprite, ref texture, isPrefixHooked); if (onEnable) { CheckSpriteRenderer(source); } } } internal void Hook_ImageChangedOnComponent(object source, ref Sprite sprite, ref Texture2D texture, bool isPrefixHooked, bool onEnable) { if (CallOrigin.ImageHooksEnabled && source.IsKnownImageType()) { HandleImage(source, ref sprite, ref texture, isPrefixHooked); if (onEnable) { CheckSpriteRenderer(source); } } } internal void Hook_ImageChanged(ref Texture2D texture, bool isPrefixHooked) { if (CallOrigin.ImageHooksEnabled && !((Object)(object)texture == (Object)null)) { Sprite sprite = null; HandleImage(null, ref sprite, ref texture, isPrefixHooked); } } private bool DiscoverComponent(object ui, TextTranslationInfo info) { if (info == null) { return true; } try { bool flag = ui.IsComponentActive(); if ((_hasValidOverrideFont || Settings.ForceUIResizing) && flag) { if (_hasValidOverrideFont) { if (_hasOverridenFont) { info.ChangeFont(ui); } else { info.UnchangeFont(ui); } } if (Settings.ForceUIResizing) { info.ResizeUI(ui, ResizeCache); _hasResizedCurrentComponentDuringDiscovery = true; } return true; } return flag; } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while handling the UI discovery."); } return false; } private void CheckSpriteRenderer(object ui) { if (Settings.EnableSpriteRendererHooking) { int frameCount = Time.frameCount; if (frameCount - 1 != _lastSpriteUpdateFrame && frameCount != _lastSpriteUpdateFrame) { _requireSpriteRendererCheckCausedBy = ui?.GetType().Name; } _lastSpriteUpdateFrame = frameCount; } } internal void SetTranslatedText(object ui, string translatedText, string originalText, TextTranslationInfo info) { info?.SetTranslatedText(translatedText); if (_isInTranslatedMode && !CallOrigin.ExpectsTextToBeReturned) { SetText(ui, translatedText, isTranslated: true, originalText, info); } } private void SetText(object ui, string text, bool isTranslated, string originalText, TextTranslationInfo info) { if (info != null && info.IsCurrentlySettingText) { return; } try { _textHooksEnabled = false; if (info != null) { info.IsCurrentlySettingText = true; } if (Settings.EnableTextPathLogging) { string path = ui.GetPath(); if (path != null) { int scope = TranslationScopeHelper.GetScope(ui); XuaLogger.AutoTranslator.Info("Setting text on '" + ui.GetType().FullName + "' to '" + text + "'"); XuaLogger.AutoTranslator.Info("Path : " + path); XuaLogger.AutoTranslator.Info("Level: " + scope); } } if (!_hasResizedCurrentComponentDuringDiscovery && info != null && (Settings.EnableUIResizing || Settings.ForceUIResizing)) { if (isTranslated || Settings.ForceUIResizing) { info.ResizeUI(ui, ResizeCache); } else { info.UnresizeUI(ui); } } ui.SetText(text, info); info?.ResetScrollIn(ui); if (info.GetIsKnownTextComponent() && originalText != null && ui != null && !ui.IsSpammingComponent()) { if (_isInTranslatedMode && isTranslated) { TranslationHelper.DisplayTranslationInfo(originalText, text); } QueueNewUntranslatedForClipboard(originalText); if (TranslationAggregatorWindow != null) { TranslationAggregatorWindow.OnNewTranslationAdded(originalText, text); } } } catch (TargetInvocationException) { } catch (NullReferenceException) { } catch (Exception ex3) { XuaLogger.AutoTranslator.Error(ex3, "An error occurred while setting text on a component."); } finally { _textHooksEnabled = true; if (info != null) { info.IsCurrentlySettingText = false; } } } private bool IsBelowMaxLength(string str) { return str.Length <= Settings.MaxCharactersPerTranslation; } private string TranslateOrQueueWebJob(object ui, string text, bool ignoreComponentState, TextTranslationInfo info) { IReadOnlyTextTranslationCache textCache = CallOrigin.GetTextCache(info, TextCache); if (info != null && info.IsStabilizingText) { return TranslateImmediate(ui, text, info, ignoreComponentState, textCache); } return TranslateOrQueueWebJobImmediate(ui, text, -1, info, info.GetSupportsStabilization(), ignoreComponentState, allowStartTranslationImmediate: false, textCache.AllowGeneratingNewTranslations, textCache, null, null); } private void HandleImage(object source, ref Sprite sprite, ref Texture2D texture, bool isPrefixHooked) { if (Settings.EnableTextureDumping) { try { DumpTexture(source, texture); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while dumping texture."); } } if (Settings.EnableTextureTranslation) { try { TranslateTexture(source, ref sprite, ref texture, isPrefixHooked, null); } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while translating texture."); } } } private void TranslateTexture(object ui, ref Sprite sprite, TextureReloadContext context) { Texture2D texture = default(Texture2D); if (ObjectExtensions.TryCastTo(ui, ref texture)) { TranslateTexture(null, ref sprite, ref texture, isPrefixHooked: false, context); return; } Texture2D texture2 = null; TranslateTexture(ui, ref sprite, ref texture2, isPrefixHooked: false, context); } private void TranslateTexture(object ui, TextureReloadContext context) { Sprite sprite = null; Texture2D texture = default(Texture2D); if (ObjectExtensions.TryCastTo(ui, ref texture)) { TranslateTexture(null, ref sprite, ref texture, isPrefixHooked: false, context); return; } Texture2D texture2 = null; TranslateTexture(ui, ref sprite, ref texture2, isPrefixHooked: false, context); } private void TranslateTexture(object source, ref Sprite sprite, ref Texture2D texture, bool isPrefixHooked, TextureReloadContext context) { try { CallOrigin.ImageHooksEnabled = false; Texture2D val = texture; texture = texture ?? source.GetTexture(); if ((Object)(object)texture == (Object)null) { return; } TextureTranslationInfo orCreateTextureTranslationInfo = texture.GetOrCreateTextureTranslationInfo(); ImageTranslationInfo orCreateImageTranslationInfo = source.GetOrCreateImageTranslationInfo(texture); string key = orCreateTextureTranslationInfo.GetKey(); if (string.IsNullOrEmpty(key)) { return; } bool flag = context != null; bool flag2 = false; bool flag3 = false; if (flag) { flag2 = context.RegisterTextureInContextAndDetermineWhetherToReload(texture); } SpriteRenderer val2 = default(SpriteRenderer); if (Settings.EnableLegacyTextureLoading && Settings.EnableSpriteRendererHooking && orCreateImageTranslationInfo != null && orCreateImageTranslationInfo.IsTranslated && ObjectExtensions.TryCastTo(source, ref val2)) { Texture2D target = orCreateTextureTranslationInfo.Original.Target; Texture2D translated = orCreateTextureTranslationInfo.Translated; if (object.Equals(texture, target) && orCreateTextureTranslationInfo.IsTranslated) { if ((Object)(object)orCreateTextureTranslationInfo.TranslatedSprite != (Object)null) { if (isPrefixHooked) { if ((Object)(object)sprite != (Object)null) { sprite = orCreateTextureTranslationInfo.TranslatedSprite; } } else { val2.sprite = orCreateTextureTranslationInfo.TranslatedSprite; } } } else if (!object.Equals(texture, translated)) { orCreateImageTranslationInfo.Reset(texture); if (orCreateTextureTranslationInfo.IsTranslated && isPrefixHooked && (Object)(object)sprite != (Object)null && (Object)(object)orCreateTextureTranslationInfo.TranslatedSprite != (Object)null) { sprite = orCreateTextureTranslationInfo.TranslatedSprite; } } } if (TextureCache.TryGetTranslatedImage(key, out var data, out var image)) { if (_isInTranslatedMode) { bool flag4 = texture.IsCompatible(image.ImageFormat); if (!orCreateTextureTranslationInfo.IsTranslated || flag2) { try { if (Settings.EnableLegacyTextureLoading || !flag4) { orCreateTextureTranslationInfo.CreateTranslatedTexture(data, image.ImageFormat); flag3 = true; } else { texture.LoadImageEx(data, image.ImageFormat, null); flag3 = true; } } finally { orCreateTextureTranslationInfo.IsTranslated = true; } } if (orCreateImageTranslationInfo != null && (!orCreateImageTranslationInfo.IsTranslated || flag)) { try { if (Settings.EnableLegacyTextureLoading || !flag4) { Sprite val3 = source.SetTexture(orCreateTextureTranslationInfo.Translated, sprite, isPrefixHooked); if ((Object)(object)val3 != (Object)null) { orCreateTextureTranslationInfo.TranslatedSprite = val3; if (isPrefixHooked && (Object)(object)sprite != (Object)null) { sprite = val3; } } } if (!isPrefixHooked) { source.SetAllDirtyEx(); } } finally { orCreateImageTranslationInfo.IsTranslated = true; } } } } else { byte[] originalData = orCreateTextureTranslationInfo.GetOriginalData(); if (originalData != null) { if (orCreateTextureTranslationInfo.IsTranslated) { try { if (Settings.EnableLegacyTextureLoading) { orCreateTextureTranslationInfo.CreateOriginalTexture(); flag3 = true; } else { texture.LoadImageEx(originalData, ImageFormat.PNG, null); flag3 = true; } } finally { orCreateTextureTranslationInfo.IsTranslated = true; } } if (orCreateImageTranslationInfo != null && orCreateImageTranslationInfo.IsTranslated) { try { Texture2D target2 = orCreateTextureTranslationInfo.Original.Target; if (Settings.EnableLegacyTextureLoading && (Object)(object)target2 != (Object)null) { source.SetTexture(target2, null, isPrefixHooked); } if (!isPrefixHooked) { source.SetAllDirtyEx(); } } finally { orCreateImageTranslationInfo.IsTranslated = true; } } } } if (!_isInTranslatedMode) { byte[] originalData2 = orCreateTextureTranslationInfo.GetOriginalData(); if (originalData2 != null) { if (orCreateTextureTranslationInfo.IsTranslated) { try { if (Settings.EnableLegacyTextureLoading) { orCreateTextureTranslationInfo.CreateOriginalTexture(); flag3 = true; } else { texture.LoadImageEx(originalData2, ImageFormat.PNG, null); flag3 = true; } } finally { orCreateTextureTranslationInfo.IsTranslated = false; } } if (orCreateImageTranslationInfo != null && orCreateImageTranslationInfo.IsTranslated) { try { Texture2D target3 = orCreateTextureTranslationInfo.Original.Target; if (Settings.EnableLegacyTextureLoading && (Object)(object)target3 != (Object)null) { source.SetTexture(target3, null, isPrefixHooked); } if (!isPrefixHooked) { source.SetAllDirtyEx(); } } finally { orCreateImageTranslationInfo.IsTranslated = false; } } } } if ((Object)(object)val == (Object)null) { texture = null; } else if (orCreateTextureTranslationInfo.UsingReplacedTexture) { if (orCreateTextureTranslationInfo.IsTranslated) { Texture2D translated2 = orCreateTextureTranslationInfo.Translated; if ((Object)(object)translated2 != (Object)null) { texture = translated2; } } else { Texture2D target4 = orCreateTextureTranslationInfo.Original.Target; if ((Object)(object)target4 != (Object)null) { texture = target4; } } } else { texture = val; } if (flag2 && flag3) { XuaLogger.AutoTranslator.Info("Reloaded texture: " + ((Object)texture).name + " (" + key + ")."); } } finally { CallOrigin.ImageHooksEnabled = true; } } private void DumpTexture(object source, Texture2D texture) { try { CallOrigin.ImageHooksEnabled = false; texture = texture ?? source.GetTexture(); if ((Object)(object)texture == (Object)null) { return; } TextureTranslationInfo orCreateTextureTranslationInfo = texture.GetOrCreateTextureTranslationInfo(); if (orCreateTextureTranslationInfo.IsDumped) { return; } try { if (ShouldTranslate(texture)) { string key = orCreateTextureTranslationInfo.GetKey(); if (!string.IsNullOrEmpty(key) && !TextureCache.IsImageRegistered(key)) { string textureName = texture.GetTextureName("Unnamed"); byte[] orCreateOriginalData = orCreateTextureTranslationInfo.GetOrCreateOriginalData(); TextureCache.RegisterImageFromData(textureName, key, orCreateOriginalData); } } } finally { orCreateTextureTranslationInfo.IsDumped = true; } } finally { CallOrigin.ImageHooksEnabled = true; } } private bool ShouldTranslate(Texture2D texture) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected I4, but got Unknown int num = (int)texture.format; if (num != 1 && num != 9) { return num != 63; } return false; } private string TranslateImmediate(object ui, string text, TextTranslationInfo info, bool ignoreComponentState, IReadOnlyTextTranslationCache tc) { if (info != null && info.IsCurrentlySettingText) { return null; } text = text ?? ui.GetText(info); string text2 = text; if (info != null && info.IsTranslated && text2 == info.TranslatedText) { return null; } bool flag = false; if (info != null) { info.Reset(text2); flag = info.ShouldIgnore; } if (StringExtensions.IsNullOrWhiteSpace(text)) { return null; } if (CheckAndFixRedirected(ui, text, info)) { return null; } int scope = TranslationScopeHelper.GetScope(ui); if (!flag && tc.IsTranslatable(text, isToken: false, scope) && (ignoreComponentState || ui.IsComponentActive())) { bool isFromSpammingComponent = ui.IsSpammingComponent(); UntranslatedText cacheKey = GetCacheKey(text, isFromSpammingComponent); if ((cacheKey.IsTemplated && !tc.IsTranslatable(cacheKey.TemplatedOriginal_Text, isToken: false, scope)) || cacheKey.IsOnlyTemplate) { string text3 = cacheKey.Untemplate(cacheKey.TemplatedOriginal_Text); bool flag2 = tc.IsPartial(cacheKey.TemplatedOriginal_Text, scope); SetTranslatedText(ui, text3, (!flag2) ? text2 : null, info); return text3; } if (tc.TryGetTranslation(cacheKey, allowRegex: false, allowToken: false, scope, out var value)) { string text4 = cacheKey.Untemplate(value); bool flag3 = tc.IsPartial(cacheKey.TemplatedOriginal_Text, scope); SetTranslatedText(ui, text4, (!flag3) ? text2 : null, info); return text4; } if (UnityTextParsers.GameLogTextParser.CanApply(ui)) { ParserResult parserResult = UnityTextParsers.GameLogTextParser.Parse(text, scope, tc); if (parserResult != null) { bool flag4 = LanguageHelper.IsTranslatable(cacheKey.TemplatedOriginal_Text); value = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult, scope, allowStartTranslationImmediate: false, allowStartTranslationLater: false, flag4 || Settings.OutputUntranslatableText, tc, null); if (value != null) { tc.IsPartial(cacheKey.TemplatedOriginal_Text, scope); SetTranslatedText(ui, value, null, info); return value; } } } } return null; } private ComponentTranslationContext InvokeOnTranslatingCallback(object textComponent, string untranslatedText, TextTranslationInfo info) { int count = _shouldIgnore.Count; if (info != null && !info.IsCurrentlySettingText && count > 0) { try { ComponentTranslationContext componentTranslationContext = new ComponentTranslationContext(textComponent, untranslatedText); info.IsCurrentlySettingText = true; for (int i = 0; i < count; i++) { _shouldIgnore[i](componentTranslationContext); if (componentTranslationContext.Behaviour != ComponentTranslationBehaviour.Default) { return componentTranslationContext; } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred during a on-translating callback."); } finally { info.IsCurrentlySettingText = false; } } return null; } void ITranslator.IgnoreTextComponent(object textComponent) { TextTranslationInfo orCreateTextTranslationInfo = textComponent.GetOrCreateTextTranslationInfo(); if (orCreateTextTranslationInfo != null) { orCreateTextTranslationInfo.ShouldIgnore = true; } } void ITranslator.UnignoreTextComponent(object textComponent) { TextTranslationInfo orCreateTextTranslationInfo = textComponent.GetOrCreateTextTranslationInfo(); if (orCreateTextTranslationInfo != null) { orCreateTextTranslationInfo.ShouldIgnore = false; } } void ITranslator.RegisterOnTranslatingCallback(Action shouldIgnore) { _shouldIgnore.Add(shouldIgnore); } void ITranslator.UnregisterOnTranslatingCallback(Action shouldIgnore) { _shouldIgnore.Remove(shouldIgnore); } void IInternalTranslator.TranslateAsync(TranslationEndpointManager endpoint, string untranslatedText, Action onCompleted) { Translate(untranslatedText, -1, endpoint, null, onCompleted, isGlobal: false, allowStartTranslateImmediate: true, allowFallback: false, null); } void ITranslator.TranslateAsync(string untranslatedText, Action onCompleted) { Translate(untranslatedText, -1, TranslationManager.CurrentEndpoint, null, onCompleted, isGlobal: true, allowStartTranslateImmediate: true, allowFallback: true, null); } void ITranslator.TranslateAsync(string untranslatedText, int scope, Action onCompleted) { Translate(untranslatedText, scope, TranslationManager.CurrentEndpoint, null, onCompleted, isGlobal: true, allowStartTranslateImmediate: true, allowFallback: true, null); } bool ITranslator.TryTranslate(string text, out string translatedText) { return TryTranslate(text, -1, out translatedText); } bool ITranslator.TryTranslate(string text, int scope, out string translatedText) { return TryTranslate(text, scope, out translatedText); } private bool TryTranslate(string text, int scope, out string translatedText) { if (scope == -1) { scope = TranslationScopeHelper.GetScope(null); } if (!StringExtensions.IsNullOrWhiteSpace(text) && TextCache.IsTranslatable(text, isToken: false, scope)) { UntranslatedText cacheKey = GetCacheKey(text, isFromSpammingComponent: false); if ((cacheKey.IsTemplated && !TextCache.IsTranslatable(cacheKey.TemplatedOriginal_Text, isToken: false, scope)) || cacheKey.IsOnlyTemplate) { string text2 = cacheKey.Untemplate(cacheKey.TemplatedOriginal_Text); translatedText = text2; return true; } if (TextCache.TryGetTranslation(cacheKey, allowRegex: true, allowToken: false, scope, out var value)) { translatedText = value; return true; } ParserResult parserResult = UnityTextParsers.RegexSplittingTextParser.Parse(text, scope, TextCache) ?? UnityTextParsers.RichTextParser.Parse(text, scope); if (parserResult != null) { translatedText = TranslateByParserResult(null, parserResult, scope, null, allowStartTranslateImmediate: false, isGlobal: true, allowFallback: false, null); return translatedText != null; } } translatedText = null; return false; } private InternalTranslationResult Translate(string text, int scope, TranslationEndpointManager endpoint, ParserTranslationContext context, Action onCompleted, bool isGlobal, bool allowStartTranslateImmediate, bool allowFallback, UntranslatedTextInfo untranslatedTextContext) { InternalTranslationResult internalTranslationResult = new InternalTranslationResult(isGlobal, onCompleted); if (isGlobal) { if (scope == -1 && context == null) { scope = TranslationScopeHelper.GetScope(null); } if (!StringExtensions.IsNullOrWhiteSpace(text) && TextCache.IsTranslatable(text, isToken: false, scope)) { UntranslatedText cacheKey = GetCacheKey(text, isFromSpammingComponent: false); if ((cacheKey.IsTemplated && !TextCache.IsTranslatable(cacheKey.TemplatedOriginal_Text, isToken: false, scope)) || cacheKey.IsOnlyTemplate) { string completed = cacheKey.Untemplate(cacheKey.TemplatedOriginal_Text); internalTranslationResult.SetCompleted(completed); return internalTranslationResult; } if (TextCache.TryGetTranslation(cacheKey, allowRegex: true, allowToken: false, scope, out var value)) { internalTranslationResult.SetCompleted(cacheKey.Untemplate(value)); return internalTranslationResult; } if (context.GetLevelsOfRecursion() < Settings.MaxTextParserRecursion) { ParserResult parserResult = UnityTextParsers.RegexSplittingTextParser.Parse(text, scope, TextCache); if (parserResult != null) { value = TranslateByParserResult(endpoint, parserResult, scope, internalTranslationResult, allowStartTranslateImmediate, internalTranslationResult.IsGlobal, allowFallback, context); if (value != null) { internalTranslationResult.SetCompleted(value); } return internalTranslationResult; } if (!context.HasBeenParsedBy(ParserResultOrigin.RichTextParser)) { parserResult = UnityTextParsers.RichTextParser.Parse(text, scope); if (parserResult != null) { value = TranslateByParserResult(endpoint, parserResult, scope, internalTranslationResult, allowStartTranslateImmediate, internalTranslationResult.IsGlobal, allowFallback, context); if (value != null) { internalTranslationResult.SetCompleted(value); } return internalTranslationResult; } } } else if (Settings.MaxTextParserRecursion != 1) { XuaLogger.AutoTranslator.Warn("Attempted to exceed maximum allowed levels of text parsing recursion!"); } bool flag = LanguageHelper.IsTranslatable(cacheKey.TemplatedOriginal_Text); if (!flag && !Settings.OutputUntranslatableText && !cacheKey.IsTemplated) { internalTranslationResult.SetCompleted(text); } else if (Settings.IsShutdown) { internalTranslationResult.SetErrorWithMessage("The plugin is shutdown."); } else if (endpoint == null) { internalTranslationResult.SetErrorWithMessage("No translator is selected."); } else if (endpoint.HasFailedDueToConsecutiveErrors) { internalTranslationResult.SetErrorWithMessage("The translation endpoint is shutdown."); } else if (!allowStartTranslateImmediate) { internalTranslationResult.SetErrorWithMessage("Could not resolve a translation at this time."); } else if (IsBelowMaxLength(text) || endpoint == TranslationManager.PassthroughEndpoint) { CreateTranslationJobFor(endpoint, null, cacheKey, internalTranslationResult, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag, allowFallback, untranslatedTextContext); } else if (Settings.OutputTooLongText) { CreateTranslationJobFor(TranslationManager.PassthroughEndpoint, null, cacheKey, internalTranslationResult, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag, allowFallback: false, untranslatedTextContext); } else { internalTranslationResult.SetErrorWithMessage("The provided text exceeds the maximum length."); } return internalTranslationResult; } internalTranslationResult.SetErrorWithMessage("The provided text (" + text + ") cannot be translated."); } else if (endpoint == null) { internalTranslationResult.SetErrorWithMessage("No translator is selected."); } else { if (!StringExtensions.IsNullOrWhiteSpace(text) && endpoint.IsTranslatable(text)) { UntranslatedText cacheKey2 = GetCacheKey(text, isFromSpammingComponent: false); if (cacheKey2.IsTemplated && !endpoint.IsTranslatable(cacheKey2.TemplatedOriginal_Text)) { internalTranslationResult.SetErrorWithMessage("This text is already considered a translation for something else."); return internalTranslationResult; } if (cacheKey2.IsOnlyTemplate) { string completed2 = cacheKey2.Untemplate(cacheKey2.TemplatedOriginal_Text); internalTranslationResult.SetCompleted(completed2); return internalTranslationResult; } if (endpoint.TryGetTranslation(cacheKey2, out var value2)) { internalTranslationResult.SetCompleted(cacheKey2.Untemplate(value2)); return internalTranslationResult; } if (context.GetLevelsOfRecursion() < Settings.MaxTextParserRecursion) { ParserResult parserResult2 = UnityTextParsers.RegexSplittingTextParser.Parse(text, -1, TextCache); if (parserResult2 != null) { value2 = TranslateByParserResult(endpoint, parserResult2, -1, internalTranslationResult, allowStartTranslateImmediate, internalTranslationResult.IsGlobal, allowFallback, context); if (value2 != null) { internalTranslationResult.SetCompleted(value2); } return internalTranslationResult; } if (!context.HasBeenParsedBy(ParserResultOrigin.RichTextParser)) { parserResult2 = UnityTextParsers.RichTextParser.Parse(text, -1); if (parserResult2 != null) { value2 = TranslateByParserResult(endpoint, parserResult2, -1, internalTranslationResult, allowStartTranslateImmediate, internalTranslationResult.IsGlobal, allowFallback, context); if (value2 != null) { internalTranslationResult.SetCompleted(value2); } return internalTranslationResult; } } } else if (Settings.MaxTextParserRecursion != 1) { XuaLogger.AutoTranslator.Warn("Attempted to exceed maximum allowed levels of text parsing recursion!"); } bool flag2 = LanguageHelper.IsTranslatable(cacheKey2.TemplatedOriginal_Text); if (!flag2 && !Settings.OutputUntranslatableText && !cacheKey2.IsTemplated) { internalTranslationResult.SetCompleted(text); } else if (Settings.IsShutdown) { internalTranslationResult.SetErrorWithMessage("The plugin is shutdown."); } else if (endpoint.HasFailedDueToConsecutiveErrors) { internalTranslationResult.SetErrorWithMessage("The translation endpoint is shutdown."); } else if (!allowStartTranslateImmediate) { internalTranslationResult.SetErrorWithMessage("Could not resolve a translation at this time."); } else if (IsBelowMaxLength(text) || endpoint == TranslationManager.PassthroughEndpoint) { CreateTranslationJobFor(endpoint, null, cacheKey2, internalTranslationResult, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag2, allowFallback, untranslatedTextContext); } else if (Settings.OutputTooLongText) { CreateTranslationJobFor(TranslationManager.PassthroughEndpoint, null, cacheKey2, internalTranslationResult, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag2, allowFallback: false, untranslatedTextContext); } else { internalTranslationResult.SetErrorWithMessage("The provided text exceeds the maximum length."); } return internalTranslationResult; } internalTranslationResult.SetErrorWithMessage("The provided text (" + text + ") cannot be translated."); } return internalTranslationResult; } private string TranslateByParserResult(TranslationEndpointManager endpoint, ParserResult result, int scope, InternalTranslationResult translationResult, bool allowStartTranslateImmediate, bool isGlobal, bool allowFallback, ParserTranslationContext parentContext) { bool allowPartial = endpoint == null && result.AllowPartialTranslation; ParserTranslationContext context = new ParserTranslationContext(null, endpoint, translationResult, result, parentContext); if (isGlobal) { return result.GetTranslationFromParts(delegate(UntranslatedTextInfo untranslatedTextInfoPart) { string untranslatedText3 = untranslatedTextInfoPart.UntranslatedText; if (StringExtensions.IsNullOrWhiteSpace(untranslatedText3) || !TextCache.IsTranslatable(untranslatedText3, isToken: true, scope)) { return untranslatedText3 ?? string.Empty; } UntranslatedText untranslatedText4 = new UntranslatedText(untranslatedText3, isFromSpammingComponent: false, removeInternalWhitespace: false, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (!TextCache.IsTranslatable(untranslatedText4.TemplatedOriginal_Text, isToken: true, scope)) { return untranslatedText4.Untemplate(untranslatedText4.TemplatedOriginal_Text) ?? string.Empty; } if (TextCache.TryGetTranslation(untranslatedText4, allowRegex: false, allowToken: true, scope, out var value2)) { return untranslatedText4.Untemplate(value2) ?? string.Empty; } if ((!Settings.OutputUntranslatableText && !LanguageHelper.IsTranslatable(untranslatedText4.TemplatedOriginal_Text) && !untranslatedText4.IsTemplated) || untranslatedText4.IsOnlyTemplate) { return untranslatedText4.Untemplate(untranslatedText4.TemplatedOriginal_Text) ?? string.Empty; } InternalTranslationResult internalTranslationResult2 = Translate(untranslatedText3, scope, endpoint, context, null, isGlobal, allowStartTranslateImmediate, allowFallback, untranslatedTextInfoPart); if (internalTranslationResult2.TranslatedText != null) { return untranslatedText4.Untemplate(internalTranslationResult2.TranslatedText) ?? string.Empty; } return allowPartial ? (untranslatedText4.Untemplate(untranslatedText4.TemplatedOriginal_Text) ?? string.Empty) : null; }); } if (endpoint == null) { return null; } return result.GetTranslationFromParts(delegate(UntranslatedTextInfo untranslatedTextInfoPart) { string untranslatedText = untranslatedTextInfoPart.UntranslatedText; if (StringExtensions.IsNullOrWhiteSpace(untranslatedText) || !endpoint.IsTranslatable(untranslatedText)) { return untranslatedText ?? string.Empty; } UntranslatedText untranslatedText2 = new UntranslatedText(untranslatedText, isFromSpammingComponent: false, removeInternalWhitespace: false, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (!endpoint.IsTranslatable(untranslatedText2.TemplatedOriginal_Text)) { return untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty; } if (endpoint.TryGetTranslation(untranslatedText2, out var value)) { return untranslatedText2.Untemplate(value) ?? string.Empty; } if ((!Settings.OutputUntranslatableText && !LanguageHelper.IsTranslatable(untranslatedText2.TemplatedOriginal_Text) && !untranslatedText2.IsTemplated) || untranslatedText2.IsOnlyTemplate) { return untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty; } InternalTranslationResult internalTranslationResult = Translate(untranslatedText, scope, endpoint, context, null, isGlobal, allowStartTranslateImmediate, allowFallback, untranslatedTextInfoPart); if (internalTranslationResult.TranslatedText != null) { return untranslatedText2.Untemplate(internalTranslationResult.TranslatedText) ?? string.Empty; } return allowPartial ? (untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty) : null; }); } private bool CheckAndFixRedirected(object ui, string text, TextTranslationInfo info) { if (Settings.RedirectedResourceDetectionStrategy == RedirectedResourceDetection.None || !LanguageHelper.HasRedirectedTexts) { return false; } if (info != null && _textHooksEnabled && !info.IsCurrentlySettingText) { if (text.IsRedirected()) { info.IsCurrentlySettingText = true; _textHooksEnabled = false; try { string text2 = text.FixRedirected(); info.RedirectedTranslations.Add(text2); ui.SetText(text2, info); return true; } finally { _textHooksEnabled = true; info.IsCurrentlySettingText = false; } } if (info.RedirectedTranslations.Contains(text)) { return true; } } return false; } private string TranslateOrQueueWebJobImmediate(object ui, string text, int scope, TextTranslationInfo info, bool allowStabilizationOnTextComponent, bool ignoreComponentState, bool allowStartTranslationImmediate, bool allowStartTranslationLater, IReadOnlyTextTranslationCache tc, UntranslatedTextInfo untranslatedTextContext, ParserTranslationContext context) { if (info != null && info.IsCurrentlySettingText) { return null; } text = text ?? ui.GetText(info); if (info != null && info.IsTranslated && text == info.TranslatedText) { return null; } bool flag = false; if (info != null) { info.Reset(text); flag = info.ShouldIgnore; } if (scope == -1 && context == null) { scope = TranslationScopeHelper.GetScope(ui); } if (StringExtensions.IsNullOrWhiteSpace(text)) { return null; } if (context == null && CheckAndFixRedirected(ui, text, info)) { return null; } if (!flag && (ignoreComponentState || ui.IsComponentActive())) { if (context == null && info != null) { ComponentTranslationContext componentTranslationContext = InvokeOnTranslatingCallback(ui, text, info); if (componentTranslationContext != null) { switch (componentTranslationContext.Behaviour) { case ComponentTranslationBehaviour.OverrideTranslatedText: { string overriddenTranslatedText = componentTranslationContext.OverriddenTranslatedText; if (overriddenTranslatedText != null) { SetTranslatedText(ui, overriddenTranslatedText, text, info); } return overriddenTranslatedText; } case ComponentTranslationBehaviour.IgnoreComponent: return null; } } } if (!tc.IsTranslatable(text, isToken: false, scope)) { return null; } bool flag2 = ui.IsSpammingComponent(); if (flag2 && !IsBelowMaxLength(text)) { return null; } UntranslatedText cacheKey = GetCacheKey(text, flag2); if ((cacheKey.IsTemplated && !tc.IsTranslatable(cacheKey.TemplatedOriginal_Text, isToken: false, scope)) || cacheKey.IsOnlyTemplate) { string text2 = cacheKey.Untemplate(cacheKey.TemplatedOriginal_Text); if (context == null) { SetTranslatedText(ui, text2, text, info); } return text2; } if (tc.TryGetTranslation(cacheKey, !flag2, allowToken: false, scope, out var value)) { string text3 = cacheKey.Untemplate(value); if (context == null) { bool flag3 = tc.IsPartial(cacheKey.TemplatedOriginal_Text, scope); SetTranslatedText(ui, text3, (!flag3) ? text : null, info); } return text3; } bool flag4 = LanguageHelper.IsTranslatable(cacheKey.TemplatedOriginal_Text); if (!flag2) { if (context.GetLevelsOfRecursion() < Settings.MaxTextParserRecursion) { if (UnityTextParsers.GameLogTextParser.CanApply(ui) && context == null) { ParserResult parserResult = UnityTextParsers.GameLogTextParser.Parse(text, scope, tc); if (parserResult != null) { value = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult, scope, allowStartTranslationImmediate, allowStartTranslationLater && !allowStabilizationOnTextComponent, flag4 || Settings.OutputUntranslatableText, tc, context); if (value != null) { if (context == null) { SetTranslatedText(ui, value, null, info); } return value; } if (context != null) { return null; } } } if (UnityTextParsers.RegexSplittingTextParser.CanApply(ui)) { ParserResult parserResult2 = UnityTextParsers.RegexSplittingTextParser.Parse(text, scope, tc); if (parserResult2 != null) { value = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult2, scope, allowStartTranslationImmediate, allowStartTranslationLater && !allowStabilizationOnTextComponent, flag4 || Settings.OutputUntranslatableText, tc, context); if (value != null) { if (context == null) { SetTranslatedText(ui, value, text, info); } return value; } if (context != null) { return null; } } } if (UnityTextParsers.RichTextParser.CanApply(ui) && !context.HasBeenParsedBy(ParserResultOrigin.RichTextParser)) { ParserResult parserResult3 = UnityTextParsers.RichTextParser.Parse(text, scope); if (parserResult3 != null) { value = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult3, scope, allowStartTranslationImmediate, allowStartTranslationLater && !allowStabilizationOnTextComponent, flag4 || Settings.OutputUntranslatableText, tc, context); if (value != null) { if (context == null) { SetTranslatedText(ui, value, text, info); } return value; } if (context != null) { return null; } } } } else if (Settings.MaxTextParserRecursion != 1) { XuaLogger.AutoTranslator.Warn("Attempted to exceed maximum allowed levels of text parsing recursion!"); } } if (!flag4 && !Settings.OutputUntranslatableText && (!cacheKey.IsTemplated || flag2)) { if (_isInTranslatedMode && !flag2) { TranslationHelper.DisplayTranslationInfo(text, null); } return text; } TranslateByEndpoint(ui, text, cacheKey, flag4, flag2, scope, info, allowStabilizationOnTextComponent, allowStartTranslationImmediate, allowStartTranslationLater, tc, untranslatedTextContext, context); } return null; } private void TranslateByEndpoint(object ui, string text, UntranslatedText textKey, bool isTranslatable, bool isSpammer, int scope, TextTranslationInfo info, bool allowStabilizationOnTextComponent, bool allowStartTranslationImmediate, bool allowStartTranslationLater, IReadOnlyTextTranslationCache tc, UntranslatedTextInfo untranslatedTextContext, ParserTranslationContext context) { TranslationEndpointManager endpoint = GetTranslationEndpoint(context, allowFallback: true); if (allowStartTranslationImmediate) { if (endpoint != null && !Settings.IsShutdown && !endpoint.HasFailedDueToConsecutiveErrors) { if (IsBelowMaxLength(text) || endpoint == TranslationManager.PassthroughEndpoint) { CreateTranslationJobFor(endpoint, ui, textKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, isTranslatable, allowFallback: true, untranslatedTextContext); } else if (Settings.OutputTooLongText) { CreateTranslationJobFor(TranslationManager.PassthroughEndpoint, ui, textKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, isTranslatable, allowFallback: false, untranslatedTextContext); } } return; } if (allowStabilizationOnTextComponent && allowStartTranslationLater && context == null) { info.IsStabilizingText = true; try { string translation; Action action = delegate(string stabilizedText) { info.IsStabilizingText = false; text = stabilizedText; TextTranslationInfo textTranslationInfo = info; if (textTranslationInfo == null || !textTranslationInfo.IsTranslated) { info?.Reset(text); if (!StringExtensions.IsNullOrWhiteSpace(stabilizedText) && (context != null || !CheckAndFixRedirected(ui, text, info)) && tc.IsTranslatable(stabilizedText, isToken: false, scope)) { UntranslatedText cacheKey = GetCacheKey(stabilizedText, isFromSpammingComponent: false); if ((cacheKey.IsTemplated && !tc.IsTranslatable(cacheKey.TemplatedOriginal_Text, isToken: false, scope)) || cacheKey.IsOnlyTemplate) { string translatedText = cacheKey.Untemplate(cacheKey.TemplatedOriginal_Text); SetTranslatedText(ui, translatedText, text, info); } else if (tc.TryGetTranslation(cacheKey, allowRegex: true, allowToken: false, scope, out translation)) { bool flag = tc.IsPartial(cacheKey.TemplatedOriginal_Text, scope); SetTranslatedText(ui, cacheKey.Untemplate(translation), (!flag) ? text : null, info); } else { bool flag2 = LanguageHelper.IsTranslatable(cacheKey.TemplatedOriginal_Text); if (UnityTextParsers.GameLogTextParser.CanApply(ui) && context == null) { ParserResult parserResult = UnityTextParsers.GameLogTextParser.Parse(stabilizedText, scope, tc); if (parserResult != null) { string text2 = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult, scope, allowStartTranslationImmediate: true, allowStartTranslationLater: false, flag2 || Settings.OutputUntranslatableText, tc, context); if (text2 != null && context == null) { SetTranslatedText(ui, text2, null, info); } return; } } if (UnityTextParsers.RegexSplittingTextParser.CanApply(ui)) { ParserResult parserResult2 = UnityTextParsers.RegexSplittingTextParser.Parse(stabilizedText, scope, tc); if (parserResult2 != null) { string text3 = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult2, scope, allowStartTranslationImmediate: true, allowStartTranslationLater: false, flag2 || Settings.OutputUntranslatableText, tc, context); if (text3 != null && context == null) { SetTranslatedText(ui, text3, text, info); } return; } } if (UnityTextParsers.RichTextParser.CanApply(ui) && !context.HasBeenParsedBy(ParserResultOrigin.RichTextParser)) { ParserResult parserResult3 = UnityTextParsers.RichTextParser.Parse(stabilizedText, scope); if (parserResult3 != null) { string text4 = TranslateOrQueueWebJobImmediateByParserResult(ui, parserResult3, scope, allowStartTranslationImmediate: true, allowStartTranslationLater: false, flag2 || Settings.OutputUntranslatableText, tc, context); if (text4 != null && context == null) { SetTranslatedText(ui, text4, text, info); } return; } } if (!flag2 && !Settings.OutputUntranslatableText && !cacheKey.IsTemplated) { if (_isInTranslatedMode && !isSpammer) { TranslationHelper.DisplayTranslationInfo(text, null); } } else if (endpoint != null && !Settings.IsShutdown && !endpoint.HasFailedDueToConsecutiveErrors) { if (IsBelowMaxLength(text) || endpoint == TranslationManager.PassthroughEndpoint) { CreateTranslationJobFor(endpoint, ui, cacheKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag2, allowFallback: true, untranslatedTextContext); } else if (Settings.OutputTooLongText) { CreateTranslationJobFor(TranslationManager.PassthroughEndpoint, ui, cacheKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, flag2, allowFallback: false, untranslatedTextContext); } } } } } }; if (endpoint?.Endpoint is PassthroughTranslateEndpoint) { action(text); return; } float delay = endpoint?.TranslationDelay ?? Settings.DefaultTranslationDelay; int maxTries = endpoint?.MaxRetries ?? Settings.DefaultMaxRetries; CoroutineHelper.Start(WaitForTextStablization(ui, info, delay, maxTries, 0, action, delegate { info.IsStabilizingText = false; })); return; } catch (Exception) { info.IsStabilizingText = false; return; } } if (!allowStartTranslationLater) { return; } float delay2 = endpoint?.TranslationDelay ?? Settings.DefaultTranslationDelay; CoroutineHelper.Start(WaitForTextStablization(textKey, delay2, delegate { if (!tc.TryGetTranslation(textKey, allowRegex: true, allowToken: false, scope, out var _)) { TranslationEndpointManager translationEndpoint = GetTranslationEndpoint(context, allowFallback: true); if (translationEndpoint != null && !Settings.IsShutdown && !translationEndpoint.HasFailedDueToConsecutiveErrors) { if (IsBelowMaxLength(text) || translationEndpoint == TranslationManager.PassthroughEndpoint) { CreateTranslationJobFor(translationEndpoint, ui, textKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, isTranslatable, allowFallback: true, untranslatedTextContext); } else if (Settings.OutputTooLongText) { CreateTranslationJobFor(TranslationManager.PassthroughEndpoint, ui, textKey, null, context, checkOtherEndpoints: true, checkSpam: true, saveResultGlobally: true, isTranslatable, allowFallback: false, untranslatedTextContext); } } } })); } private TranslationEndpointManager GetTranslationEndpoint(ParserTranslationContext context, bool allowFallback) { TranslationEndpointManager translationEndpointManager = context?.Endpoint ?? TranslationManager.CurrentEndpoint; if (allowFallback && translationEndpointManager != null && translationEndpointManager.HasFailedDueToConsecutiveErrors && TranslationManager.IsFallbackAvailableFor(translationEndpointManager)) { XuaLogger.AutoTranslator.Warn("Falling back to fallback translator in order to perform translation."); translationEndpointManager = TranslationManager.FallbackEndpoint; } return translationEndpointManager; } private string TranslateOrQueueWebJobImmediateByParserResult(object ui, ParserResult result, int scope, bool allowStartTranslationImmediate, bool allowStartTranslationLater, bool allowImmediateCaching, IReadOnlyTextTranslationCache tc, ParserTranslationContext parentContext) { bool allowPartial = TranslationManager.CurrentEndpoint == null && result.AllowPartialTranslation; ParserTranslationContext context = new ParserTranslationContext(ui, TranslationManager.CurrentEndpoint, null, result, parentContext); string translationFromParts = result.GetTranslationFromParts(delegate(UntranslatedTextInfo untranslatedTextInfoPart) { string untranslatedText = untranslatedTextInfoPart.UntranslatedText; if (StringExtensions.IsNullOrWhiteSpace(untranslatedText) || !tc.IsTranslatable(untranslatedText, isToken: true, scope)) { return untranslatedText ?? string.Empty; } UntranslatedText untranslatedText2 = new UntranslatedText(untranslatedText, isFromSpammingComponent: false, removeInternalWhitespace: false, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (!tc.IsTranslatable(untranslatedText2.TemplatedOriginal_Text, isToken: true, scope)) { return untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty; } if (tc.TryGetTranslation(untranslatedText2, allowRegex: false, allowToken: true, scope, out var value)) { return untranslatedText2.Untemplate(value) ?? string.Empty; } if ((!Settings.OutputUntranslatableText && !LanguageHelper.IsTranslatable(untranslatedText2.TemplatedOriginal_Text) && !untranslatedText2.IsTemplated) || untranslatedText2.IsOnlyTemplate) { return untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty; } value = TranslateOrQueueWebJobImmediate(ui, untranslatedText, scope, null, allowStabilizationOnTextComponent: false, ignoreComponentState: true, allowStartTranslationImmediate, allowStartTranslationLater, tc, untranslatedTextInfoPart, context); if (value != null) { return untranslatedText2.Untemplate(value) ?? string.Empty; } return allowPartial ? (untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text) ?? string.Empty) : null; }); try { if (Settings.CacheParsedTranslations && allowImmediateCaching && parentContext == null && translationFromParts != null && context.CachedCombinedResult()) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Parsed translation cached: '" + context.Result.OriginalText + "' => '" + translationFromParts + "'"); } TextCache.AddTranslationToCache(context.Result.OriginalText, translationFromParts, persistToDisk: false, TranslationType.Full, scope); context.Endpoint.AddTranslationToCache(context.Result.OriginalText, translationFromParts); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while attempting to cache a parsed translation."); } return translationFromParts; } private IEnumerator WaitForTextStablization(object ui, TextTranslationInfo info, float delay, int maxTries, int currentTries, Action onTextStabilized, Action onMaxTriesExceeded) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__96(0) { ui = ui, info = info, delay = delay, maxTries = maxTries, currentTries = currentTries, onTextStabilized = onTextStabilized, onMaxTriesExceeded = onMaxTriesExceeded }; } private IEnumerator WaitForTextStablization(UntranslatedText textKey, float delay, Action onTextStabilized, Action onFailed = null) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__97(0) { <>4__this = this, textKey = textKey, delay = delay, onTextStabilized = onTextStabilized, onFailed = onFailed }; } private void Awake() { if (!_initialized) { _initialized = true; try { Initialize(); ManualHook(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An unexpected error occurred during plugin initialization."); } } } private TextTranslationCache GetTextCacheFor(string assemblyName) { if (!PluginTextCaches.TryGetValue(assemblyName, out var value)) { value = new TextTranslationCache(assemblyName); PluginTextCaches[assemblyName] = value; } return value; } void ITranslationRegistry.RegisterPluginSpecificTranslations(Assembly assembly, StreamTranslationPackage package) { TextTranslationCache textCacheFor = GetTextCacheFor(assembly.GetName().Name); textCacheFor.RegisterPackage(package); textCacheFor.LoadTranslationFiles(); HooksSetup.InstallComponentBasedPluginTranslationHooks(); HooksSetup.InstallIMGUIBasedPluginTranslationHooks(assembly, final: true); } void ITranslationRegistry.RegisterPluginSpecificTranslations(Assembly assembly, KeyValuePairTranslationPackage package) { TextTranslationCache textCacheFor = GetTextCacheFor(assembly.GetName().Name); textCacheFor.RegisterPackage(package); textCacheFor.LoadTranslationFiles(); HooksSetup.InstallComponentBasedPluginTranslationHooks(); HooksSetup.InstallIMGUIBasedPluginTranslationHooks(assembly, final: true); } void ITranslationRegistry.EnablePluginTranslationFallback(Assembly assembly) { TextTranslationCache textCacheFor = GetTextCacheFor(assembly.GetName().Name); textCacheFor.AllowFallback = true; textCacheFor.DefaultAllowFallback = true; HooksSetup.InstallComponentBasedPluginTranslationHooks(); HooksSetup.InstallIMGUIBasedPluginTranslationHooks(assembly, final: true); } private IEnumerator HookLoadedPlugins() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__103(0) { <>4__this = this }; } public void Start() { if (!_started) { _started = true; Awake(); try { CoroutineHelper.Start(HookLoadedPlugins()); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An unexpected error occurred during plugin start."); } } } private void HandleInputSafe() { if (_inputSupported) { try { HandleInput(); } catch (Exception ex) { _inputSupported = false; XuaLogger.AutoTranslator.Warn(ex, "Input API is not available!"); } } } private void HandleInput() { if (!UnityInput.Current.GetKey((KeyCode)308) && !UnityInput.Current.GetKey((KeyCode)307)) { return; } bool key = UnityInput.Current.GetKey((KeyCode)306); if (UnityInput.Current.GetKeyDown((KeyCode)116)) { ToggleTranslation(); } else if (UnityInput.Current.GetKeyDown((KeyCode)102)) { ToggleFont(); } else if (UnityInput.Current.GetKeyDown((KeyCode)114)) { ReloadTranslations(); } else if (UnityInput.Current.GetKeyDown((KeyCode)117)) { ManualHook(); } else if (UnityInput.Current.GetKeyDown((KeyCode)113)) { RebootPlugin(); } else if (UnityInput.Current.GetKeyDown((KeyCode)48) || UnityInput.Current.GetKeyDown((KeyCode)256)) { if (MainWindow != null) { MainWindow.IsShown = !MainWindow.IsShown; } } else if (UnityInput.Current.GetKeyDown((KeyCode)49) || UnityInput.Current.GetKeyDown((KeyCode)257)) { ToggleTranslationAggregator(); } else if (key) { if (UnityInput.Current.GetKeyDown((KeyCode)265)) { Settings.SimulateError = !Settings.SimulateError; } else if (UnityInput.Current.GetKeyDown((KeyCode)264)) { Settings.SimulateDelayedError = !Settings.SimulateDelayedError; } else if (UnityInput.Current.GetKeyDown((KeyCode)263)) { PrintSceneInformation(); } else if (UnityInput.Current.GetKeyDown((KeyCode)262)) { PrintObjects(); } } } public void Update() { try { int frameCount = Time.frameCount; TranslationManager.Update(); if (frameCount % 36000 == 0 && CachedKeys.Count > 0) { CachedKeys.Clear(); } if (UnityFeatures.SupportsClipboard) { CopyToClipboard(); } if (!Settings.IsShutdown) { EnableAutoTranslator(); SpamChecker.Update(); UpdateSpriteRenderers(); IncrementBatchOperations(); KickoffTranslations(); TranslationAggregatorWindow?.Update(); } if (_translationReloadRequest) { _translationReloadRequest = false; ReloadTranslations(); } if (frameCount % 100 == 0 && TranslationManager.OngoingTranslations == 0 && TranslationManager.UnstartedTranslations == 0) { ConnectionTrackingWebClient.CheckServicePoints(); } HandleInputSafe(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred in Update callback. "); } } private void PrintSceneInformation() { SceneLoadInformation sceneLoadInformation = new SceneLoadInformation(); XuaLogger.AutoTranslator.Info("Active Scene: " + sceneLoadInformation.ActiveScene.Name + " (" + sceneLoadInformation.ActiveScene.Id + ")"); XuaLogger.AutoTranslator.Info("Loaded Scenes:"); for (int i = 0; i < sceneLoadInformation.LoadedScenes.Count; i++) { SceneInformation sceneInformation = sceneLoadInformation.LoadedScenes[i]; XuaLogger.AutoTranslator.Info(i + ": " + sceneInformation.Name + " (" + sceneInformation.Id + ")"); } } public void OnGUI() { InitializeGUI(); try { DisableAutoTranslator(); if (MainWindow != null) { try { if (MainWindow.IsShown) { MainWindow.OnGUI(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred in XUnity.AutoTranslator UI. Disabling the UI."); MainWindow = null; } } if (TranslationAggregatorWindow != null) { try { if (TranslationAggregatorWindow.IsShown) { TranslationAggregatorWindow.OnGUI(); } } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred in Translation Aggregator UI. Disabling the UI."); TranslationAggregatorWindow = null; } } if (TranslationAggregatorOptionsWindow == null) { return; } try { if (TranslationAggregatorOptionsWindow.IsShown) { TranslationAggregatorOptionsWindow.OnGUI(); } } catch (Exception ex3) { XuaLogger.AutoTranslator.Error(ex3, "An error occurred in Translation Aggregator Options UI. Disabling the UI."); TranslationAggregatorOptionsWindow = null; } } finally { EnableAutoTranslator(); } } private void RebootPlugin() { foreach (TranslationEndpointManager configuredEndpoint in TranslationManager.ConfiguredEndpoints) { configuredEndpoint.ConsecutiveErrors = 0; } XuaLogger.AutoTranslator.Info("Rebooted Auto Translator."); } private void KickoffTranslations() { TranslationManager.KickoffTranslations(); } private void OnJobFailed(TranslationJob job) { foreach (KeyAnd translationResult2 in job.TranslationResults) { translationResult2.Item.SetErrorWithMessage(job.ErrorMessage ?? "Unknown error."); } foreach (ParserTranslationContext context in job.Contexts) { InternalTranslationResult translationResult = context.TranslationResult; if (translationResult != null && context.Jobs.Any((TranslationJob x) => x.State == TranslationJobState.Failed)) { translationResult.SetErrorWithMessage(job.ErrorMessage ?? "Unknown error."); } } } private void OnJobCompleted(TranslationJob job) { TranslationType translationType = job.TranslationType; bool shouldPersistTranslation = job.ShouldPersistTranslation; if (job.Key.IsTemplated && Settings.GenerateStaticSubstitutionTranslations) { bool flag = false; if (job.Key.IsFromSpammingComponent) { flag = true; if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText); } foreach (KeyAnd component in job.Components) { UntranslatedText key = component.Key; if (key.IsFromSpammingComponent) { if (!flag) { flag = true; if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText); } } else { string key2 = key.Untemplate(key.TemplatedOriginal_Text); string value = key.Untemplate(job.TranslatedText); if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(key2, value, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(key2, value); } } foreach (KeyAnd translationResult in job.TranslationResults) { UntranslatedText key3 = translationResult.Key; if (key3.IsFromSpammingComponent) { if (!flag) { flag = true; if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText); } } else { string key4 = key3.Untemplate(key3.TemplatedOriginal_Text); string value2 = key3.Untemplate(job.TranslatedText); if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(key4, value2, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(key4, value2); } } } else { if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText, shouldPersistTranslation, translationType, -1); } job.Endpoint.AddTranslationToCache(job.Key.TemplatedOriginal_Text, job.TranslatedText); } foreach (KeyAnd translationResult2 in job.TranslationResults) { if (!string.IsNullOrEmpty(job.TranslatedText)) { translationResult2.Item.SetCompleted(translationResult2.Key.Untemplate(job.TranslatedText)); } else { translationResult2.Item.SetEmptyResponse(); } } foreach (KeyAnd component2 in job.Components) { object item = component2.Item; UntranslatedText key5 = component2.Key; try { TextTranslationInfo orCreateTextTranslationInfo = item.GetOrCreateTextTranslationInfo(); if (item.GetText(orCreateTextTranslationInfo) == key5.Original_Text && !string.IsNullOrEmpty(job.TranslatedText)) { SetTranslatedText(item, key5.Untemplate(job.TranslatedText), key5.Original_Text, orCreateTextTranslationInfo); } } catch (NullReferenceException) { } } foreach (ParserTranslationContext context in job.Contexts) { ParserTranslationContext ancestorContext = context.GetAncestorContext(); if (!ancestorContext.HasAllJobsCompleted()) { continue; } try { TextTranslationInfo orCreateTextTranslationInfo2 = ancestorContext.Component.GetOrCreateTextTranslationInfo(); string text = ancestorContext.Component.GetText(orCreateTextTranslationInfo2); ParserResult result = ancestorContext.Result; string text2 = ((ancestorContext.TranslationResult != null) ? TranslateByParserResult(ancestorContext.Endpoint, result, -1, null, allowStartTranslateImmediate: false, ancestorContext.TranslationResult.IsGlobal, allowFallback: false, null) : TranslateOrQueueWebJobImmediateByParserResult(ancestorContext.Component, result, -1, allowStartTranslationImmediate: false, allowStartTranslationLater: false, allowImmediateCaching: false, TextCache, null)); if (!string.IsNullOrEmpty(text2)) { if (ancestorContext.CachedCombinedResult()) { if (job.SaveResultGlobally) { TextCache.AddTranslationToCache(ancestorContext.Result.OriginalText, text2, ancestorContext.PersistCombinedResult(), TranslationType.Full, -1); } job.Endpoint.AddTranslationToCache(ancestorContext.Result.OriginalText, text2); } if (text == result.OriginalText) { SetTranslatedText(ancestorContext.Component, text2, ancestorContext.Result.OriginalText, orCreateTextTranslationInfo2); } if (ancestorContext.TranslationResult != null) { ancestorContext.TranslationResult.SetCompleted(text2); } } else if (ancestorContext.TranslationResult != null) { ancestorContext.TranslationResult.SetEmptyResponse(); } } catch (NullReferenceException) { } } Settings.TranslationCount++; if (!Settings.IsShutdown && Settings.TranslationCount > Settings.MaxTranslationsBeforeShutdown) { Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error($"Maximum translations ({Settings.MaxTranslationsBeforeShutdown}) per session reached. Shutting plugin down."); TranslationManager.ClearAllJobs(); } } private UntranslatedText GetCacheKey(string originalText, bool isFromSpammingComponent) { if (isFromSpammingComponent && CachedKeys.Count < Settings.MaxImguiKeyCacheCount) { if (!CachedKeys.TryGetValue(originalText, out var value)) { value = new UntranslatedText(originalText, isFromSpammingComponent, !isFromSpammingComponent, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); CachedKeys.Add(originalText, value); } return value; } return new UntranslatedText(originalText, isFromSpammingComponent, !isFromSpammingComponent, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); } private void ReloadTranslations() { try { TextCache.PruneMainTranslationFile(); LoadTranslations(reload: true); TextureReloadContext context = new TextureReloadContext(); foreach (KeyValuePair allRegisteredObject in ExtensionDataHelper.GetAllRegisteredObjects()) { object key = allRegisteredObject.Key; try { TextTranslationInfo textTranslationInfo = allRegisteredObject.Value as TextTranslationInfo; if (!textTranslationInfo.GetIsKnownTextComponent() || !key.IsComponentActive()) { goto IL_0204; } int scope = TranslationScopeHelper.GetScope(key); if (textTranslationInfo == null || StringExtensions.IsNullOrWhiteSpace(textTranslationInfo.OriginalText)) { goto IL_0204; } bool flag = false; string originalText = textTranslationInfo.OriginalText; try { UntranslatedText cacheKey = GetCacheKey(originalText, isFromSpammingComponent: false); if (TextCache.TryGetTranslation(cacheKey, allowRegex: true, allowToken: false, scope, out var value)) { textTranslationInfo.UnresizeUI(key); SetTranslatedText(allRegisteredObject.Key, cacheKey.Untemplate(value), null, textTranslationInfo); flag = true; continue; } if (!UnityTextParsers.GameLogTextParser.CanApply(key)) { goto IL_0130; } ParserResult parserResult = UnityTextParsers.GameLogTextParser.Parse(originalText, scope, TextCache); if (parserResult == null) { goto IL_0130; } string text = TranslateOrQueueWebJobImmediateByParserResult(key, parserResult, scope, allowStartTranslationImmediate: false, allowStartTranslationLater: false, allowImmediateCaching: false, TextCache, null); if (text == null) { goto IL_0130; } textTranslationInfo.UnresizeUI(key); SetTranslatedText(key, text, null, textTranslationInfo); flag = true; goto end_IL_0089; IL_018e: if (UnityTextParsers.RichTextParser.CanApply(key)) { ParserResult parserResult2 = UnityTextParsers.RichTextParser.Parse(originalText, scope); if (parserResult2 != null) { string text2 = TranslateOrQueueWebJobImmediateByParserResult(key, parserResult2, scope, allowStartTranslationImmediate: false, allowStartTranslationLater: false, allowImmediateCaching: false, TextCache, null); if (text2 != null) { textTranslationInfo.UnresizeUI(key); SetTranslatedText(key, text2, null, textTranslationInfo); flag = true; continue; } goto IL_0204; } goto IL_0204; } goto IL_0204; IL_0130: if (!UnityTextParsers.RegexSplittingTextParser.CanApply(key)) { goto IL_018e; } ParserResult parserResult3 = UnityTextParsers.RegexSplittingTextParser.Parse(originalText, scope, TextCache); if (parserResult3 == null) { goto IL_018e; } string text3 = TranslateOrQueueWebJobImmediateByParserResult(key, parserResult3, scope, allowStartTranslationImmediate: false, allowStartTranslationLater: false, allowImmediateCaching: false, TextCache, null); if (text3 == null) { goto IL_018e; } textTranslationInfo.UnresizeUI(key); SetTranslatedText(key, text3, null, textTranslationInfo); flag = true; end_IL_0089:; } finally { if (!flag) { SetText(key, textTranslationInfo.OriginalText, isTranslated: false, null, textTranslationInfo); Hook_TextChanged(key, onEnable: false); } } goto end_IL_0038; IL_0204: if (Settings.EnableTextureTranslation && (key is Texture2D || key.IsKnownImageType())) { TranslateTexture(key, context); } end_IL_0038:; } catch (Exception) { ExtensionDataHelper.Remove(key); } } } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while reloading translations."); } } private void ToggleFont() { if (!_hasValidOverrideFont) { return; } _hasOverridenFont = !_hasOverridenFont; List> allRegisteredObjects = ExtensionDataHelper.GetAllRegisteredObjects(); XuaLogger.AutoTranslator.Info($"Toggling fonts of {allRegisteredObjects.Count} objects."); if (_hasOverridenFont) { foreach (KeyValuePair item in allRegisteredObjects) { if (item.Value is TextTranslationInfo textTranslationInfo) { object key = item.Key; try { if (key.IsComponentActive()) { textTranslationInfo.ChangeFont(key); } } catch (Exception) { ExtensionDataHelper.Remove(key); } } } return; } foreach (KeyValuePair item2 in allRegisteredObjects) { if (!(item2.Value is TextTranslationInfo textTranslationInfo2)) { continue; } object key2 = item2.Key; try { if (key2.IsComponentActive()) { textTranslationInfo2.UnchangeFont(key2); } } catch (Exception) { ExtensionDataHelper.Remove(key2); } } } private void ToggleTranslation() { _isInTranslatedMode = !_isInTranslatedMode; List> allRegisteredObjects = ExtensionDataHelper.GetAllRegisteredObjects(); XuaLogger.AutoTranslator.Info($"Toggling translations of {allRegisteredObjects.Count} objects."); if (_isInTranslatedMode) { foreach (KeyValuePair item in allRegisteredObjects) { object key = item.Key; try { TextTranslationInfo textTranslationInfo = item.Value as TextTranslationInfo; if (textTranslationInfo.GetIsKnownTextComponent() && key.IsComponentActive() && textTranslationInfo != null && textTranslationInfo.IsTranslated) { SetText(key, textTranslationInfo.TranslatedText, isTranslated: true, null, textTranslationInfo); } if (Settings.EnableTextureTranslation && Settings.EnableTextureToggling && (key is Texture2D || key.IsKnownImageType())) { TranslateTexture(key, null); } } catch (Exception) { ExtensionDataHelper.Remove(key); } } return; } foreach (KeyValuePair item2 in allRegisteredObjects) { object key2 = item2.Key; try { TextTranslationInfo textTranslationInfo2 = item2.Value as TextTranslationInfo; if (textTranslationInfo2.GetIsKnownTextComponent() && key2.IsComponentActive() && textTranslationInfo2 != null && textTranslationInfo2.IsTranslated) { SetText(key2, textTranslationInfo2.OriginalText, isTranslated: false, null, textTranslationInfo2); } if (Settings.EnableTextureTranslation && Settings.EnableTextureToggling) { TranslateTexture(key2, null); } } catch (Exception) { ExtensionDataHelper.Remove(key2); } } } private void CopyToClipboard() { if (Settings.CopyToClipboard && _textsToCopyToClipboardOrdered.Count > 0 && (_textsToCopyToClipboardOrdered.Count > 5 || Time.realtimeSinceStartup - _clipboardUpdated > Settings.ClipboardDebounceTime)) { try { ClipboardHelper.CopyToClipboard(_textsToCopyToClipboardOrdered, Settings.MaxClipboardCopyCharacters); } finally { _textsToCopyToClipboard.Clear(); _textsToCopyToClipboardOrdered.Clear(); } } } private void PrintObjects() { using FileStream stream = File.Open(Path.Combine(Paths.GameRoot, "hierarchy.txt"), FileMode.Create); using StreamWriter streamWriter = new StreamWriter(stream); foreach (GameObject allRoot in GetAllRoots()) { TraverseChildren(streamWriter, allRoot, ""); } streamWriter.Flush(); } private void ManualHook() { ManualHookForComponents(); ManualHookForTextures(); } private void ManualHookForComponents() { foreach (GameObject allRoot in GetAllRoots()) { TraverseChildrenManualHook(allRoot); } } private void ManualHookForTextures() { if (Settings.EnableTextureScanOnSceneLoad && (Settings.EnableTextureTranslation || Settings.EnableTextureDumping)) { Texture2D[] array = ComponentHelper.FindObjectsOfType(); for (int i = 0; i < array.Length; i++) { Texture2D texture = array[i]; Hook_ImageChanged(ref texture, isPrefixHooked: false); } } } private IEnumerable GetAllRoots() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__124(-2); } private void TraverseChildren(StreamWriter writer, GameObject obj, string identation) { if (!((Object)(object)obj != (Object)null)) { return; } string text = LayerMask.LayerToName(obj.layer); string arg = string.Join(", ", (from x in obj.GetComponents().Select(delegate(Component x) { string text2 = null; Type type = ((object)x)?.GetType(); if ((object)type != null) { text2 = type.Name; TextTranslationInfo orCreateTextTranslationInfo = x.GetOrCreateTextTranslationInfo(); string text3 = x.GetText(orCreateTextTranslationInfo); if (!string.IsNullOrEmpty(text3)) { text2 = text2 + " (" + text3 + ")"; } } return text2; }) where x != null select x).ToArray()); string value = string.Format("{0,-50} {1,100}", identation + ((Object)obj).name + " [" + text + "]", arg); writer.WriteLine(value); if ((Object)(object)obj.transform != (Object)null) { for (int i = 0; i < obj.transform.childCount; i++) { Transform child = obj.transform.GetChild(i); TraverseChildren(writer, ((Component)child).gameObject, identation + " "); } } } private void TraverseChildrenManualHook(GameObject obj) { if (!((Object)(object)obj != (Object)null)) { return; } Component[] components = obj.GetComponents(); foreach (Component val in components) { object obj2 = val.CreateDerivedProxyIfRequiredAndPossible(); if (obj2 != null) { Hook_TextChanged(obj2, onEnable: false); } if ((Settings.EnableTextureTranslation || Settings.EnableTextureDumping) && val.IsKnownImageType()) { Texture2D texture = null; Hook_ImageChangedOnComponent(val, ref texture, isPrefixHooked: false, onEnable: false); } } if ((Object)(object)obj.transform != (Object)null) { for (int j = 0; j < obj.transform.childCount; j++) { Transform child = obj.transform.GetChild(j); TraverseChildrenManualHook(((Component)child).gameObject); } } } public void DisableAutoTranslator() { _temporarilyDisabled = true; } public void EnableAutoTranslator() { _temporarilyDisabled = false; } internal bool IsTemporarilyDisabled() { return _temporarilyDisabled; } private void OnDestroy() { try { RedirectedDirectory.Uninitialize(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while uninitializing redirected directory cache."); } try { TextCache.Dispose(); } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while disposing translation text cache."); } try { TextureCache.Dispose(); } catch (Exception ex3) { XuaLogger.AutoTranslator.Error(ex3, "An error occurred while disposing translation texture cache."); } foreach (TranslationEndpointManager allEndpoint in TranslationManager.AllEndpoints) { try { if (allEndpoint.Endpoint is IDisposable disposable) { disposable.Dispose(); } } catch (Exception ex4) { XuaLogger.AutoTranslator.Error(ex4, "An error occurred while disposing endpoint."); } } } } public static class AutoTranslator { internal static IInternalTranslator Internal => AutoTranslationPlugin.Current; public static ITranslator Default => AutoTranslationPlugin.Current; } public static class AutoTranslatorSettings { public static string UserAgent => Settings.UserAgent; public static string SourceLanguage => Settings.FromLanguage; public static string DestinationLanguage => Settings.Language; public static bool IsDumpingRedirectedResourcesEnabled => Settings.EnableDumping; public static string DefaultRedirectedResourcePath => Settings.RedirectedResourcesPath; } public static class AutoTranslatorState { public static int TranslationCount => Settings.TranslationCount; public static bool PluginInitialized { get; private set; } public static event Action PluginInitializationCompleted; internal static void OnPluginInitializationCompleted() { if (PluginInitialized) { return; } PluginInitialized = true; if (AutoTranslatorState.PluginInitializationCompleted == null) { return; } try { AutoTranslatorState.PluginInitializationCompleted(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error("Subscriber crash in PluginInitializationCompleted event: " + ex); } } } internal static class CallOrigin { public static bool ImageHooksEnabled; public static bool ExpectsTextToBeReturned; public static IReadOnlyTextTranslationCache TextCache; private static readonly HashSet BreakingAssemblies; static CallOrigin() { ImageHooksEnabled = true; ExpectsTextToBeReturned = false; TextCache = null; BreakingAssemblies = new HashSet(); try { BreakingAssemblies.AddRange(from x in AppDomain.CurrentDomain.GetAssemblies() where x.IsAssemblyCsharp() || x.IsAssemblyCsharpFirstpass() select x); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while scanning for game assemblies."); } } internal static IReadOnlyTextTranslationCache GetTextCache(TextTranslationInfo info, TextTranslationCache generic) { if (info != null) { return info.TextCache ?? generic; } return TextCache ?? generic; } public static void AssociateSubHierarchyWithTransformInfo(Transform root, TransformInfo info) { Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ExtensionDataHelper.SetExtensionData((object)componentsInChildren[i], info); } ((Component)root).gameObject.SetTextCacheForAllObjectsInHierachy(info.TextCache); } public static void SetTextCacheForAllObjectsInHierachy(this GameObject go, IReadOnlyTextTranslationCache cache) { try { foreach (Component allTextComponentsInChild in go.GetAllTextComponentsInChildren()) { allTextComponentsInChild.CreateDerivedProxyIfRequiredAndPossible().GetOrCreateTextTranslationInfo().TextCache = cache; } TransformInfo transformInfo = new TransformInfo { TextCache = cache }; Transform[] componentsInChildren = go.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ExtensionDataHelper.SetExtensionData((object)componentsInChildren[i], transformInfo); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while scanning object hierarchy for text components."); } } public static IReadOnlyTextTranslationCache CalculateTextCacheFromStackTrace(GameObject parent) { try { StackTrace stackTrace = new StackTrace(2); Dictionary pluginTextCaches = AutoTranslationPlugin.Current.PluginTextCaches; if (pluginTextCaches == null) { return null; } StackFrame[] frames = stackTrace.GetFrames(); int num = frames.Length; for (int i = 0; i < num; i++) { MethodBase method = frames[i].GetMethod(); if ((object)method != null) { Assembly assembly = method.DeclaringType.Assembly; if (BreakingAssemblies.Contains(assembly)) { break; } string name = assembly.GetName().Name; if (pluginTextCaches.TryGetValue(name, out var value)) { return AutoTranslationPlugin.Current.TextCache.GetOrCreateCompositeCache(value); } } } if ((Object)(object)parent != (Object)null) { return ExtensionDataHelper.GetExtensionData((object)parent.transform)?.TextCache; } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while calculating text translation cache from stack trace."); } return null; } } internal static class ClrFeatures { internal static bool SupportsNet4x { get; } internal static bool SupportsReflectionEmit { get; } static ClrFeatures() { try { SupportsNet4x = (object)ClrTypes.Task != null; } catch (Exception) { } try { TestReflectionEmit(); SupportsReflectionEmit = true; } catch (Exception) { SupportsReflectionEmit = false; } } private static void TestReflectionEmit() { _ = default(Label) == default(Label); } } internal enum ComponentTranslationBehaviour { Default = 1, OverrideTranslatedText, IgnoreComponent } public class ComponentTranslationContext { public object Component { get; } public string OriginalText { get; } public string OverriddenTranslatedText { get; private set; } internal ComponentTranslationBehaviour Behaviour { get; private set; } internal ComponentTranslationContext(object component, string originalText) { Component = component; OriginalText = originalText; } public void ResetBehaviour() { Behaviour = ComponentTranslationBehaviour.Default; OverriddenTranslatedText = null; } public void OverrideTranslatedText(string translation) { Behaviour = ComponentTranslationBehaviour.OverrideTranslatedText; OverriddenTranslatedText = translation; } public void IgnoreComponent() { Behaviour = ComponentTranslationBehaviour.IgnoreComponent; OverriddenTranslatedText = null; } } internal class CompositeTextTranslationCache : IReadOnlyTextTranslationCache { private IReadOnlyTextTranslationCache _first; private IReadOnlyTextTranslationCache _second; public bool AllowGeneratingNewTranslations => _first.AllowFallback; public bool AllowFallback => _first.AllowFallback; public CompositeTextTranslationCache(IReadOnlyTextTranslationCache first, IReadOnlyTextTranslationCache second) { _first = first; _second = second; } public bool IsTranslatable(string text, bool isToken, int scope) { if (!_first.IsTranslatable(text, isToken, scope)) { if (_first.AllowFallback) { return _second.IsTranslatable(text, isToken, scope); } return false; } return true; } public bool IsPartial(string text, int scope) { if (!_first.IsPartial(text, scope)) { if (_first.AllowFallback) { return _second.IsPartial(text, scope); } return false; } return true; } public bool TryGetTranslation(UntranslatedText key, bool allowRegex, bool allowToken, int scope, out string value) { if (!_first.TryGetTranslation(key, allowRegex, allowToken, scope, out value)) { if (_first.AllowFallback) { return _second.TryGetTranslation(key, allowRegex, allowToken, scope, out value); } return false; } return true; } public bool TryGetTranslationSplitter(string text, int scope, out Match match, out RegexTranslationSplitter splitter) { if (!_first.TryGetTranslationSplitter(text, scope, out match, out splitter)) { if (_first.AllowFallback) { return _second.TryGetTranslationSplitter(text, scope, out match, out splitter); } return false; } return true; } } internal class DefaultPluginEnvironment : IPluginEnvironment { private IniFile _file; private string _configPath; private string _dataFolder; public IniFile Preferences => _file ?? (_file = ReloadConfig()); public string TranslationPath => _dataFolder; public string ConfigPath => _dataFolder; public bool AllowDefaultInitializeHarmonyDetourBridge { get; } public DefaultPluginEnvironment(bool allowDefaultInitializeHarmonyDetourBridge) { _dataFolder = Path.Combine(Paths.GameRoot, "AutoTranslator"); _configPath = Path.Combine(_dataFolder, "Config.ini"); AllowDefaultInitializeHarmonyDetourBridge = allowDefaultInitializeHarmonyDetourBridge; } public void SaveConfig() { _file.Save(_configPath); } public IniFile ReloadConfig() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!File.Exists(_configPath)) { return (IniFile)(((object)_file) ?? ((object)new IniFile())); } IniFile val = IniFile.FromFile(_configPath); if (_file == null) { return _file = val; } _file.Merge(val); return _file; } } internal static class HarmonyLoader { public static void Load() { try { Harmony12Loader.Load(); } catch { } } } internal static class Harmony12Loader { public static void Load() { _ = AccessTools.all; } } internal interface IInternalTranslator : ITranslator { void TranslateAsync(TranslationEndpointManager endpoint, string untranslatedText, Action onCompleted); } internal class ImageTranslationInfo { public bool IsTranslated { get; set; } public WeakReference Original { get; private set; } public void Initialize(Texture2D texture) { Original = WeakReference.Create(texture); } public void Reset(Texture2D newTexture) { IsTranslated = false; Original = WeakReference.Create(newTexture); } } public interface IMonoBehaviour : IMonoBehaviour_Update { void Start(); void OnGUI(); } public interface IMonoBehaviour_Update { void Update(); } internal class InternalTranslationResult : IEnumerator { private readonly Action _onCompleted; internal bool IsGlobal { get; private set; } public bool IsCompleted { get; private set; } public string TranslatedText { get; private set; } public string ErrorMessage { get; private set; } public bool HasError => ErrorMessage != null; public object Current => null; internal InternalTranslationResult(bool isGlobal, Action onCompleted) { IsGlobal = isGlobal; _onCompleted = onCompleted; } internal void SetCompleted(string translatedText) { if (!IsCompleted) { IsCompleted = true; SetCompletedInternal(translatedText); } } internal void SetEmptyResponse() { SetError("Received empty response."); } internal void SetErrorWithMessage(string errorMessage) { SetError(errorMessage); } private void SetError(string errorMessage) { if (!IsCompleted) { IsCompleted = true; SetErrorInternal(errorMessage); } } private void SetErrorInternal(string errorMessage) { ErrorMessage = errorMessage ?? "Unknown error"; try { _onCompleted?.Invoke(new TranslationResult(null, ErrorMessage)); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while notifying of translation failure."); } } private void SetCompletedInternal(string translatedText) { TranslatedText = translatedText; try { _onCompleted?.Invoke(new TranslationResult(TranslatedText, null)); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while notifying of translation completion."); } } public bool MoveNext() { return !IsCompleted; } public void Reset() { } } public interface IPluginEnvironment { string TranslationPath { get; } string ConfigPath { get; } IniFile Preferences { get; } bool AllowDefaultInitializeHarmonyDetourBridge { get; } void SaveConfig(); } internal interface IReadOnlyTextTranslationCache { bool AllowGeneratingNewTranslations { get; } bool AllowFallback { get; } bool IsTranslatable(string text, bool isToken, int scope); bool IsPartial(string text, int scope); bool TryGetTranslation(UntranslatedText key, bool allowRegex, bool allowToken, int scope, out string value); bool TryGetTranslationSplitter(string text, int scope, out Match match, out RegexTranslationSplitter splitter); } public interface ITranslator { void TranslateAsync(string untranslatedText, Action onCompleted); void TranslateAsync(string untranslatedText, int scope, Action onCompleted); bool TryTranslate(string untranslatedText, out string translatedText); bool TryTranslate(string untranslatedText, int scope, out string translatedText); void IgnoreTextComponent(object textComponent); void UnignoreTextComponent(object textComponent); void RegisterOnTranslatingCallback(Action context); void UnregisterOnTranslatingCallback(Action context); } internal static class Kernel32 { [DllImport("kernel32.dll", SetLastError = true)] public static extern bool AllocConsole(); [DllImport("kernel32.dll")] public static extern bool FreeConsole(); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetStdHandle(int nStdHandle); [DllImport("kernel32.dll", SetLastError = true)] public static extern bool SetStdHandle(int nStdHandle, IntPtr hConsoleOutput); [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] public static extern IntPtr CreateFile(string fileName, int desiredAccess, int shareMode, IntPtr securityAttributes, int creationDisposition, int flagsAndAttributes, IntPtr templateFile); [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] public static extern bool CloseHandle(IntPtr handle); [DllImport("kernel32.dll")] public static extern IntPtr SetConsoleOutputCP(uint codepage); [DllImport("kernel32.dll", SetLastError = true)] public static extern int WideCharToMultiByte(uint codePage, uint dwFlags, [In][MarshalAs(UnmanagedType.LPArray)] char[] lpWideCharStr, int cchWideChar, [Out][MarshalAs(UnmanagedType.LPArray)] byte[] lpMultiByteStr, int cbMultiByte, IntPtr lpDefaultChar, IntPtr lpUsedDefaultChar); [DllImport("kernel32.dll", SetLastError = true)] public static extern int MultiByteToWideChar(uint codePage, uint dwFlags, [In][MarshalAs(UnmanagedType.LPArray)] byte[] lpMultiByteStr, int cbMultiByte, [Out][MarshalAs(UnmanagedType.LPArray)] char[] lpWideCharStr, int cchWideChar); } public class KeyValuePairTranslationPackage { private List> _cachedEntries; public string Name { get; } private IEnumerable> Entries { get; } private bool AllowMultipleIterations { get; } public KeyValuePairTranslationPackage(string name, IEnumerable> entries, bool allowMultipleIterations) { Name = name; Entries = entries; AllowMultipleIterations = allowMultipleIterations; } internal IEnumerable> GetIterableEntries() { if (!AllowMultipleIterations) { if (_cachedEntries == null) { _cachedEntries = Entries.ToList(); } return _cachedEntries; } return Entries; } } internal class ParserTranslationContext { public ParserResult Result { get; private set; } public HashSet Jobs { get; private set; } public InternalTranslationResult TranslationResult { get; private set; } public object Component { get; private set; } public TranslationEndpointManager Endpoint { get; private set; } public ParserTranslationContext ParentContext { get; private set; } public List ChildrenContexts { get; private set; } public int LevelsOfRecursion { get; private set; } public ParserTranslationContext(object component, TranslationEndpointManager endpoint, InternalTranslationResult translationResult, ParserResult result, ParserTranslationContext parentContext) { Jobs = new HashSet(); ChildrenContexts = new List(); Component = component; Result = result; Endpoint = endpoint; TranslationResult = translationResult; ParentContext = parentContext; parentContext?.ChildrenContexts.Add(this); ParserTranslationContext parserTranslationContext = this; while (parserTranslationContext != null) { parserTranslationContext = parserTranslationContext.ParentContext; LevelsOfRecursion++; } } private ParserResult GetHighestPriorityResult() { ParserResult parserResult = Result; int num = parserResult.Priority; ParserTranslationContext parserTranslationContext = this; while ((parserTranslationContext = parserTranslationContext.ParentContext) != null) { ParserResult result = parserTranslationContext.Result; int priority = result.Priority; if (priority > num) { num = priority; parserResult = result; } } return parserResult; } public bool CachedCombinedResult() { return GetHighestPriorityResult().CacheCombinedResult; } public bool PersistCombinedResult() { return GetHighestPriorityResult().PersistCombinedResult; } public bool HasAllJobsCompleted() { bool flag = Jobs.All((TranslationJob x) => x.State == TranslationJobState.Succeeded); if (flag) { foreach (ParserTranslationContext childrenContext in ChildrenContexts) { flag = childrenContext.HasAllJobsCompleted(); if (!flag) { return false; } } } return flag; } } internal static class ParserTranslationContextExtensions { public static bool HasBeenParsedBy(this ParserTranslationContext context, ParserResultOrigin parser) { for (ParserTranslationContext parserTranslationContext = context; parserTranslationContext != null; parserTranslationContext = parserTranslationContext.ParentContext) { if (parserTranslationContext.Result.Origin == parser) { return true; } } return false; } public static int GetLevelsOfRecursion(this ParserTranslationContext context) { return context?.LevelsOfRecursion ?? 0; } public static ParserTranslationContext GetAncestorContext(this ParserTranslationContext context) { ParserTranslationContext parserTranslationContext = context; for (ParserTranslationContext parentContext = parserTranslationContext.ParentContext; parentContext != null; parentContext = parserTranslationContext.ParentContext) { parserTranslationContext = parentContext; } return parserTranslationContext; } } internal enum PersistRichTextMode { Final, Fragment } internal static class PluginEnvironment { public static IPluginEnvironment Current; } public static class PluginLoader { internal class Bootstrapper : MonoBehaviour { public event Action Destroyed = delegate { }; private void Start() { Object.Destroy((Object)(object)((Component)this).gameObject); } private void OnDestroy() { this.Destroyed?.Invoke(); } } internal static AutoTranslationPlugin Plugin; internal static MonoBehaviour MonoBehaviour; private static bool _loaded; private static bool _bootstrapped; public static IMonoBehaviour LoadWithConfig(IPluginEnvironment config) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Expected O, but got Unknown if (!_loaded) { _loaded = true; PluginEnvironment.Current = config; GameObject val = new GameObject("___XUnityAutoTranslator") { hideFlags = (HideFlags)61 }; Plugin = val.AddComponent(); MonoBehaviour = (MonoBehaviour)(object)Plugin; Object.DontDestroyOnLoad((Object)val); } return Plugin; } public static IMonoBehaviour Load() { return LoadWithConfig(new DefaultPluginEnvironment(allowDefaultInitializeHarmonyDetourBridge: true)); } public static IMonoBehaviour Load(bool allowDefaultInitializeHarmonyDetourBridge) { return LoadWithConfig(new DefaultPluginEnvironment(allowDefaultInitializeHarmonyDetourBridge)); } public static void LoadThroughBootstrapper() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) if (!_bootstrapped) { _bootstrapped = true; new GameObject("Bootstrapper").AddComponent().Destroyed += Bootstrapper_Destroyed; } } private static void Bootstrapper_Destroyed() { Load(); } } internal enum RedirectedResourceDetection { None, AppendMongolianVowelSeparator, AppendMongolianVowelSeparatorAndRemoveAppended, AppendMongolianVowelSeparatorAndRemoveAll } internal class RegexTranslation { public Regex CompiledRegex { get; set; } public string Original { get; set; } public string Translation { get; set; } public string Key { get; set; } public string Value { get; set; } public RegexTranslation(string key, string value) { Key = key; Value = value; if (key.StartsWith("r:")) { key = key.Substring(2, key.Length - 2); } int num = key.IndexOf('"'); if (num != -1) { num++; int num2 = key.LastIndexOf('"'); if (num2 == num - 1) { throw new Exception("Splitter regex with key: '" + Key + "' starts with a \" but does not end with a \"."); } key = key.Substring(num, num2 - num); } if (value.StartsWith("r:")) { value = value.Substring(2, value.Length - 2); } num = value.IndexOf('"'); if (num != -1) { num++; int num3 = value.LastIndexOf('"'); if (num3 == num - 1) { throw new Exception("Splitter regex with value: '" + Value + "' starts with a \" but does not end with a \"."); } value = value.Substring(num, num3 - num); } CompiledRegex = new Regex(key, AutoTranslationPlugin.RegexCompiledSupportedFlag); Original = key; Translation = value; } } internal sealed class SafeFileWatcher : IDisposable { private int _counter; private FileSystemWatcher _watcher; private bool _disposed; private object _sync = new object(); private Timer _timer; private readonly string _directory; public event Action DirectoryUpdated; public SafeFileWatcher(string directory) { _directory = directory; _timer = new Timer(RaiseEvent, null, -1, -1); EnableWatcher(); } public void EnableWatcher() { if (_watcher == null) { _watcher = new FileSystemWatcher(_directory); _watcher.Changed += Watcher_Changed; _watcher.Created += Watcher_Created; _watcher.Deleted += Watcher_Deleted; _watcher.EnableRaisingEvents = true; } } public void DisableWatcher() { if (_watcher != null) { _watcher.EnableRaisingEvents = false; _watcher.Dispose(); _watcher = null; } } public void RaiseEvent(object state) { this.DirectoryUpdated?.Invoke(); } public void Disable() { int num = Interlocked.Increment(ref _counter); UpdateRaisingEvents(num == 0); } public void Enable() { int num = Interlocked.Decrement(ref _counter); UpdateRaisingEvents(num == 0); } private void Watcher_Deleted(object sender, FileSystemEventArgs e) { _timer.Change(1000, -1); } private void Watcher_Created(object sender, FileSystemEventArgs e) { FileInfo file = new FileInfo(e.FullPath); WaitForFile(file); _timer.Change(1000, -1); } private void Watcher_Changed(object sender, FileSystemEventArgs e) { _timer.Change(1000, -1); } private void UpdateRaisingEvents(bool enabled) { lock (_sync) { if (enabled) { EnableWatcher(); } else { DisableWatcher(); } } } private void WaitForFile(FileInfo file) { while (IsFileLocked(file)) { Thread.Sleep(100); } } private bool IsFileLocked(FileInfo file) { try { using (file.Open(FileMode.Open, FileAccess.ReadWrite, FileShare.None)) { } } catch (IOException) { return true; } return false; } private void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _watcher?.Dispose(); _watcher = null; _timer.Dispose(); } _disposed = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } internal static class SettingsTranslationsInitializer { public static void LoadTranslations() { Settings.Replacements.Clear(); Settings.Preprocessors.Clear(); Directory.CreateDirectory(Settings.TranslationsPath); string fullName = new FileInfo(Settings.SubstitutionFilePath).FullName; string fullName2 = new FileInfo(Settings.PreprocessorsFilePath).FullName; string fullName3 = new FileInfo(Settings.PostprocessorsFilePath).FullName; LoadTranslationsInFile(fullName, isSubstitutionFile: true, isPreprocessorFile: false, isPostprocessorsFile: false); LoadTranslationsInFile(fullName2, isSubstitutionFile: false, isPreprocessorFile: true, isPostprocessorsFile: false); LoadTranslationsInFile(fullName3, isSubstitutionFile: false, isPreprocessorFile: false, isPostprocessorsFile: true); } private static void LoadTranslationsInFile(string fullFileName, bool isSubstitutionFile, bool isPreprocessorFile, bool isPostprocessorsFile) { if (File.Exists(fullFileName)) { using (FileStream stream = File.OpenRead(fullFileName)) { LoadTranslationsInStream(stream, fullFileName, isSubstitutionFile, isPreprocessorFile, isPostprocessorsFile); return; } } Directory.CreateDirectory(new FileInfo(fullFileName).Directory.FullName); using FileStream fileStream = File.Create(fullFileName); fileStream.Write(new byte[3] { 239, 187, 191 }, 0, 3); fileStream.Close(); } private static void LoadTranslationsInStream(Stream stream, string fullFileName, bool isSubstitutionFile, bool isPreprocessorFile, bool isPostProcessorFile) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Loading texts: " + fullFileName + "."); } StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); TranslationFileLoadingContext translationFileLoadingContext = new TranslationFileLoadingContext(); string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { if (!translationFileLoadingContext.IsApplicable()) { continue; } try { string[] array2 = TextHelper.ReadTranslationLineAndDecode(text); if (array2 == null) { continue; } string text2 = array2[0]; string value = array2[1]; if (string.IsNullOrEmpty(text2)) { continue; } if (isSubstitutionFile) { if (!string.IsNullOrEmpty(value)) { Settings.Replacements[text2] = value; } } else if (isPreprocessorFile) { Settings.Preprocessors[text2] = value; } else if (isPostProcessorFile) { Settings.Postprocessors[text2] = value; } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while reading translation: '" + text + "'."); } } } } public class SimpleTextTranslationCache { [CompilerGenerated] private sealed class d__29 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public SimpleTextTranslationCache <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__29(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; SimpleTextTranslationCache simpleTextTranslationCache = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = CoroutineHelper.CreateWaitForSeconds(1f); <>1__state = 1; return true; case 1: <>1__state = -1; simpleTextTranslationCache._currentScheduledTask = null; ThreadPool.QueueUserWorkItem(simpleTextTranslationCache.SaveNewTranslationsToDisk); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } protected readonly Dictionary _translations = new Dictionary(); private List _defaultRegexes = new List(); private HashSet _registeredRegexes = new HashSet(); private static object _writeToFileSync = new object(); private Dictionary _newTranslations = new Dictionary(); private Coroutine _currentScheduledTask; private bool _shouldOverrideEntireFile; public string LoadedFile { get; } public bool IsDirectory { get; } public virtual bool IsEmpty => _translations.Count + _defaultRegexes.Count == 0; public SimpleTextTranslationCache(string file, bool loadTranslationsInFile) { LoadedFile = file; IsDirectory = false; if (loadTranslationsInFile) { LoadTranslationFiles(overrideLaterWithEarlier: true); } } public SimpleTextTranslationCache(string fileOrDirectory, bool loadTranslationsInFile, bool isDirectory, bool allowTranslationOverride) { LoadedFile = fileOrDirectory; IsDirectory = isDirectory; if (loadTranslationsInFile) { LoadTranslationFiles(allowTranslationOverride); } } public SimpleTextTranslationCache(string outputFile, IEnumerable inputStreams, bool allowTranslationOverride, bool closeStreams) { LoadedFile = outputFile; IsDirectory = false; if (inputStreams != null) { LoadTranslationStreams(inputStreams, allowTranslationOverride, closeStreams); } } internal void LoadTranslationFiles(bool overrideLaterWithEarlier) { try { if (IsDirectory) { foreach (string item in from x in Directory.GetFiles(LoadedFile, "*.txt") orderby x select x) { LoadTranslationsInFile(item, overrideLaterWithEarlier); } return; } LoadTranslationsInFile(LoadedFile, overrideLaterWithEarlier); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations."); } } internal void LoadTranslationStreams(IEnumerable streams, bool overrideLaterWithEarlier, bool closeStreams) { foreach (Stream stream in streams) { try { LoadTranslationsInStream(stream, overrideLaterWithEarlier, closeStreams); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations."); } } } private void LoadTranslationsInFile(string fullFileName, bool allowOverride) { if (File.Exists(fullFileName)) { LoadTranslationsInStream(File.OpenRead(fullFileName), allowOverride, closeStream: true); } } private void LoadTranslationsInStream(Stream stream, bool allowOverride, bool closeStream) { try { string[] array = new StreamReader(stream, Encoding.UTF8).ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { try { string[] array2 = TextHelper.ReadTranslationLineAndDecode(text); if (array2 == null) { continue; } string text2 = array2[0]; string text3 = array2[1]; if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3) || !(text2 != text3)) { continue; } if (text2.StartsWith("r:")) { try { RegexTranslation regex = new RegexTranslation(text2, text3); AddTranslationRegex(regex); } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while constructing regex translation: '" + text + "'."); } } else { AddTranslationInternal(text2, text3.MakeRedirected(), allowOverride); } } catch (Exception ex2) { XuaLogger.AutoTranslator.Warn(ex2, "An error occurred while reading translation: '" + text + "'."); } } } finally { if (closeStream) { stream.Dispose(); } } } private void AddTranslationRegex(RegexTranslation regex) { if (!_registeredRegexes.Contains(regex.Original)) { _registeredRegexes.Add(regex.Original); _defaultRegexes.Add(regex); } } private void AddTranslationInternal(string key, string value, bool allowOverride) { if (key != null && value != null && (allowOverride || !HasTranslated(key))) { AddTranslation(key, value); } } protected virtual bool HasTranslated(string key) { return _translations.ContainsKey(key); } protected virtual void AddTranslation(string key, string value) { _translations[key] = value; } [Obsolete("Do not use. Function only exists in case someone calls it through reflection.")] private void AddTranslation(string key, string value, bool allowOverride) { if (key != null && value != null && (allowOverride || !HasTranslated(key))) { AddTranslation(key, value); } } public virtual void AddTranslationToCache(string key, string value) { bool flag = HasTranslated(key); if (!flag) { AddTranslationInternal(key, value.MakeRedirected(), allowOverride: false); QueueNewTranslationForDisk(key, value, flag); } } private void QueueNewTranslationForDisk(string key, string value, bool hadTranslated) { lock (_newTranslations) { _newTranslations[key] = value; if (hadTranslated) { _shouldOverrideEntireFile = true; } if (_currentScheduledTask != null) { CoroutineHelper.Stop(_currentScheduledTask); } _currentScheduledTask = CoroutineHelper.Start(ScheduleFileWriting()); } } private IEnumerator ScheduleFileWriting() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__29(0) { <>4__this = this }; } internal void SaveNewTranslationsToDisk(object state) { bool flag = false; if (_newTranslations.Count <= 0) { return; } Dictionary dictionary; lock (_newTranslations) { dictionary = _newTranslations.ToDictionary((KeyValuePair x) => x.Key, (KeyValuePair x) => x.Value); _newTranslations.Clear(); if (_shouldOverrideEntireFile) { flag = true; _shouldOverrideEntireFile = false; lock (_translations) { foreach (KeyValuePair translation in _translations) { if (!dictionary.ContainsKey(translation.Key)) { dictionary[translation.Key] = translation.Value; } } foreach (RegexTranslation defaultRegex in _defaultRegexes) { if (!dictionary.ContainsKey(defaultRegex.Key)) { dictionary[defaultRegex.Key] = defaultRegex.Value; } } } } } lock (_writeToFileSync) { Directory.CreateDirectory(new FileInfo(LoadedFile).Directory.FullName); using FileStream stream = File.Open(LoadedFile, flag ? FileMode.Create : FileMode.Append, FileAccess.Write); using StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); foreach (KeyValuePair item in dictionary) { streamWriter.WriteLine(TextHelper.Encode(item.Key) + "=" + TextHelper.Encode(item.Value)); } streamWriter.Flush(); } } public virtual bool TryGetTranslation(string untranslatedText, bool allowRegex, out string value) { UntranslatedText untranslatedText2 = new UntranslatedText(untranslatedText, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: false, Settings.TemplateAllNumberAway); string text = null; string text2 = null; string text3 = null; string text4 = null; bool flag; lock (_translations) { if (untranslatedText2.IsTemplated && !untranslatedText2.IsFromSpammingComponent) { string key = text ?? (text = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text)); flag = _translations.TryGetValue(key, out value); if (flag) { return flag; } if ((object)untranslatedText2.TemplatedOriginal_Text != untranslatedText2.TemplatedOriginal_Text_ExternallyTrimmed) { key = text3 ?? (text3 = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text_ExternallyTrimmed)); flag = _translations.TryGetValue(key, out value); if (flag) { string text5 = untranslatedText2.LeadingWhitespace + value + untranslatedText2.TrailingWhitespace; if (text == null) { text = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text); } value = text5; return flag; } } if ((object)untranslatedText2.TemplatedOriginal_Text != untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed) { key = text2 ?? (text2 = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed)); flag = _translations.TryGetValue(key, out value); if (flag) { string text5 = value; if (text == null) { text = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text); } value = text5; return flag; } } if ((object)untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed != untranslatedText2.TemplatedOriginal_Text_FullyTrimmed) { key = text4 ?? (text4 = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text_FullyTrimmed)); flag = _translations.TryGetValue(key, out value); if (flag) { string text5 = untranslatedText2.LeadingWhitespace + value + untranslatedText2.TrailingWhitespace; if (text == null) { text = untranslatedText2.Untemplate(untranslatedText2.TemplatedOriginal_Text); } value = text5; return flag; } } } flag = _translations.TryGetValue(untranslatedText2.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)untranslatedText2.TemplatedOriginal_Text != untranslatedText2.TemplatedOriginal_Text_ExternallyTrimmed) { flag = _translations.TryGetValue(untranslatedText2.TemplatedOriginal_Text_ExternallyTrimmed, out value); if (flag) { string text5 = untranslatedText2.LeadingWhitespace + value + untranslatedText2.TrailingWhitespace; value = text5; return flag; } } if ((object)untranslatedText2.TemplatedOriginal_Text != untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed) { flag = _translations.TryGetValue(untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { return flag; } } if ((object)untranslatedText2.TemplatedOriginal_Text_InternallyTrimmed != untranslatedText2.TemplatedOriginal_Text_FullyTrimmed) { flag = _translations.TryGetValue(untranslatedText2.TemplatedOriginal_Text_FullyTrimmed, out value); if (flag) { string text5 = untranslatedText2.LeadingWhitespace + value + untranslatedText2.TrailingWhitespace; value = text5; return flag; } } if (allowRegex) { for (int num = _defaultRegexes.Count - 1; num > -1; num--) { RegexTranslation regexTranslation = _defaultRegexes[num]; try { if (regexTranslation.CompiledRegex.Match(untranslatedText2.TemplatedOriginal_Text).Success) { value = regexTranslation.CompiledRegex.Replace(untranslatedText2.TemplatedOriginal_Text, regexTranslation.Translation).MakeRedirected(); return true; } } catch (Exception ex) { _defaultRegexes.RemoveAt(num); XuaLogger.AutoTranslator.Error(ex, "Failed while attempting to replace or match text of regex '" + regexTranslation.Original + "'. Removing that regex from the cache."); } } } } return flag; } } internal class SpamChecker { private int[] _currentTranslationsQueuedPerSecondRollingWindow = new int[Settings.TranslationQueueWatchWindow]; private float? _timeExceededThreshold; private float _translationsQueuedPerSecond; private string[] _previouslyQueuedText = new string[Settings.PreviousTextStaggerCount]; private int _staggerTextCursor; private int _concurrentStaggers; private int _lastStaggerCheckFrame = -1; private int _frameForLastQueuedTranslation = -1; private int _consecutiveFramesTranslated; private int _secondForQueuedTranslation = -1; private int _consecutiveSecondsTranslated; private TranslationManager _translationManager; public SpamChecker(TranslationManager translationManager) { _translationManager = translationManager; } public void PerformChecks(string untranslatedText, TranslationEndpointManager endpoint) { CheckStaggerText(untranslatedText); CheckConsecutiveFrames(); CheckConsecutiveSeconds(endpoint); CheckThresholds(endpoint); } public void Update() { PeriodicResetFrameCheck(); ResetThresholdTimerIfRequired(); } private void CheckConsecutiveSeconds(TranslationEndpointManager endpoint) { int num = (int)Time.time; if (num - 1 == _secondForQueuedTranslation) { _consecutiveSecondsTranslated++; if (_consecutiveSecondsTranslated > Settings.MaximumConsecutiveSecondsTranslated && endpoint.EnableSpamChecks) { _translationManager.ClearAllJobs(); Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error($"SPAM DETECTED: Translations were queued every second for more than {Settings.MaximumConsecutiveSecondsTranslated} consecutive seconds. Shutting down plugin."); } } else if (num != _secondForQueuedTranslation) { _consecutiveSecondsTranslated = 0; } _secondForQueuedTranslation = num; } private void CheckConsecutiveFrames() { int frameCount = Time.frameCount; if (frameCount - 1 == _frameForLastQueuedTranslation) { _consecutiveFramesTranslated++; if (_consecutiveFramesTranslated > Settings.MaximumConsecutiveFramesTranslated) { _translationManager.ClearAllJobs(); Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error($"SPAM DETECTED: Translations were queued every frame for more than {Settings.MaximumConsecutiveFramesTranslated} consecutive frames. Shutting down plugin."); } } else if (frameCount != _frameForLastQueuedTranslation && _consecutiveFramesTranslated > 0) { _consecutiveFramesTranslated--; } _frameForLastQueuedTranslation = frameCount; } private void PeriodicResetFrameCheck() { if ((int)Time.time % 100 == 0) { _consecutiveFramesTranslated = 0; } } private void CheckStaggerText(string untranslatedText) { int frameCount = Time.frameCount; if (frameCount == _lastStaggerCheckFrame) { return; } _lastStaggerCheckFrame = frameCount; bool flag = false; for (int i = 0; i < _previouslyQueuedText.Length; i++) { string text = _previouslyQueuedText[i]; if (text != null && StringExtensions.RemindsOf(untranslatedText, text)) { flag = true; break; } } if (flag) { _concurrentStaggers++; if (_concurrentStaggers > Settings.MaximumStaggers) { _translationManager.ClearAllJobs(); Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error("SPAM DETECTED: Text that is 'scrolling in' is being translated. Disable that feature. Shutting down plugin."); } } else { _concurrentStaggers = 0; } _previouslyQueuedText[_staggerTextCursor % _previouslyQueuedText.Length] = untranslatedText; _staggerTextCursor++; } private void CheckThresholds(TranslationEndpointManager endpoint) { if (_translationManager.UnstartedTranslations > Settings.MaxUnstartedJobs) { _translationManager.ClearAllJobs(); Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error($"SPAM DETECTED: More than {Settings.MaxUnstartedJobs} queued for translations due to unknown reasons. Shutting down plugin."); } float time = Time.time; int num = (int)(time - Time.deltaTime) % Settings.TranslationQueueWatchWindow; int num2 = (int)time % Settings.TranslationQueueWatchWindow; if (num != num2) { _currentTranslationsQueuedPerSecondRollingWindow[num2] = 0; } _currentTranslationsQueuedPerSecondRollingWindow[num2]++; int num3 = _currentTranslationsQueuedPerSecondRollingWindow.Sum(); _translationsQueuedPerSecond = (float)num3 / (float)Settings.TranslationQueueWatchWindow; if (_translationsQueuedPerSecond > Settings.MaxTranslationsQueuedPerSecond) { if (!_timeExceededThreshold.HasValue) { _timeExceededThreshold = time; } if (time - _timeExceededThreshold.Value > (float)Settings.MaxSecondsAboveTranslationThreshold && endpoint.EnableSpamChecks) { _translationManager.ClearAllJobs(); Settings.IsShutdown = true; XuaLogger.AutoTranslator.Error($"SPAM DETECTED: More than {Settings.MaxTranslationsQueuedPerSecond} translations per seconds queued for a {Settings.MaxSecondsAboveTranslationThreshold} second period. Shutting down plugin."); } } else { _timeExceededThreshold = null; } } private void ResetThresholdTimerIfRequired() { float time = Time.time; int num = (int)(time - Time.deltaTime) % Settings.TranslationQueueWatchWindow; int num2 = (int)time % Settings.TranslationQueueWatchWindow; if (num != num2) { _currentTranslationsQueuedPerSecondRollingWindow[num2] = 0; } int num3 = _currentTranslationsQueuedPerSecondRollingWindow.Sum(); _translationsQueuedPerSecond = (float)num3 / (float)Settings.TranslationQueueWatchWindow; if (_translationsQueuedPerSecond <= Settings.MaxTranslationsQueuedPerSecond) { _timeExceededThreshold = null; } } } public sealed class StreamTranslationPackage : IDisposable { private Stream _cachedStream; private bool disposedValue; public string Name { get; } private Stream Stream { get; set; } private bool AllowMultipleIterations { get; } public StreamTranslationPackage(string name, Stream stream, bool allowMultipleIterations) { if (allowMultipleIterations && !stream.CanSeek) { throw new ArgumentException("Cannot iterate a non-seekable stream multiple times.", "allowMultipleIterations"); } Name = name; Stream = stream; AllowMultipleIterations = allowMultipleIterations; } internal Stream GetReadableStream() { if (!AllowMultipleIterations) { if (_cachedStream == null) { _cachedStream = new MemoryStream(StreamExtensions.ReadFully(Stream, 0)); Stream.Dispose(); Stream = null; } return _cachedStream; } return Stream; } private void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { Stream?.Dispose(); } Stream = null; disposedValue = true; } } public void Dispose() { Dispose(disposing: true); } } internal class TemplatedString { public string Template { get; private set; } public Dictionary Arguments { get; private set; } public TemplatedString(string template, Dictionary arguments) { Template = template; Arguments = arguments; } public string Untemplate(string text) { foreach (KeyValuePair argument in Arguments) { text = text.Replace(argument.Key, argument.Value); } return text; } public string PrepareUntranslatedText(string untranslatedText) { foreach (KeyValuePair argument in Arguments) { string key = argument.Key; string newValue = CreateTranslatorFriendlyKey(key); untranslatedText = untranslatedText.Replace(key, newValue); } return untranslatedText; } public string FixTranslatedText(string translatedText, bool useTranslatorFriendlyArgs) { foreach (KeyValuePair argument in Arguments) { string key = argument.Key; string translatorFriendlyKey = (useTranslatorFriendlyArgs ? CreateTranslatorFriendlyKey(key) : key); translatedText = ReplaceApproximateMatches(translatedText, translatorFriendlyKey, key); } return translatedText; } public static string CreateTranslatorFriendlyKey(string key) { char c = key[2]; return "ZM" + (char)(c + 2) + "Z"; } public static string ReplaceApproximateMatches(string translatedText, string translatorFriendlyKey, string key) { int num = translatorFriendlyKey.Length - 1; int num2 = num; int num3 = num; for (int num4 = translatedText.Length - 1; num4 >= 0; num4--) { char c = translatedText[num4]; if (c != ' ' && c != '\u3000') { if ((c = char.ToUpperInvariant(c)) == char.ToUpperInvariant(translatorFriendlyKey[num2]) || c == char.ToUpperInvariant(translatorFriendlyKey[num2 = num])) { if (num2 == num) { num3 = num4; } num2--; } if (num2 < 0) { int count = num3 + 1 - num4; translatedText = translatedText.Remove(num4, count).Insert(num4, key); num2 = num; } } } return translatedText; } } [Flags] internal enum TextPostProcessing { None = 0, ReplaceMacronWithCircumflex = 1, RemoveAllDiacritics = 2, RemoveApostrophes = 4, ReplaceWideCharacters = 8, ReplaceHtmlEntities = 0x10 } internal sealed class TextTranslationCache : IReadOnlyTextTranslationCache, IDisposable { private struct TranslationCharacterToken { public char Character { get; set; } public bool IsVariable { get; set; } public TranslationCharacterToken(char c, bool isVariable) { Character = c; IsVariable = isVariable; } } public class TranslationDictionaries { public Dictionary TokenTranslations { get; } public Dictionary ReverseTokenTranslations { get; } public Dictionary Translations { get; } public Dictionary ReverseTranslations { get; } public List DefaultRegexes { get; } public HashSet RegisteredRegexes { get; } public List SplitterRegexes { get; } public HashSet RegisteredSplitterRegexes { get; } public HashSet FailedRegexLookups { get; set; } public TranslationDictionaries() { Translations = new Dictionary(); ReverseTranslations = new Dictionary(); DefaultRegexes = new List(); RegisteredRegexes = new HashSet(); TokenTranslations = new Dictionary(); ReverseTokenTranslations = new Dictionary(); SplitterRegexes = new List(); RegisteredSplitterRegexes = new HashSet(); FailedRegexLookups = new HashSet(); } } private Dictionary _compositeCaches = new Dictionary(); private static readonly List _kvpPackages = new List(); private static readonly List _streamPackages = new List(); private Dictionary _staticTranslations = new Dictionary(); private Dictionary _translations = new Dictionary(); private Dictionary _reverseTranslations = new Dictionary(); private Dictionary _tokenTranslations = new Dictionary(); private Dictionary _reverseTokenTranslations = new Dictionary(); private HashSet _partialTranslations = new HashSet(); private List _defaultRegexes = new List(); private HashSet _registeredRegexes = new HashSet(); private HashSet _failedRegexLookups = new HashSet(); private List _splitterRegexes = new List(); private HashSet _registeredSplitterRegexes = new HashSet(); private Dictionary _scopedTranslations = new Dictionary(); private object _writeToFileSync = new object(); private Dictionary _newTranslations = new Dictionary(); private bool disposedValue; private readonly DirectoryInfo _pluginDirectory; private SafeFileWatcher _fileWatcher; public bool DefaultAllowFallback { get; internal set; } public bool AllowFallback { get; internal set; } public bool AllowGeneratingNewTranslations { get; private set; } public bool HasLoadedInMemoryTranslations { get { if (_kvpPackages.Count <= 0) { return _streamPackages.Count > 0; } return true; } } public event Action TextTranslationFileChanged; public TextTranslationCache() { AllowGeneratingNewTranslations = true; AllowFallback = false; DefaultAllowFallback = false; LoadStaticTranslations(); if (Settings.ReloadTranslationsOnFileChange) { try { Directory.CreateDirectory(Settings.TranslationsPath); _fileWatcher = new SafeFileWatcher(Settings.TranslationsPath); _fileWatcher.DirectoryUpdated += FileWatcher_DirectoryUpdated; } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing translation file watching for text."); } } MaintenanceHelper.AddMaintenanceFunction((Action)SaveNewTranslationsToDisk, 1); } private void FileWatcher_DirectoryUpdated() { this.TextTranslationFileChanged?.Invoke(); } public TextTranslationCache(DirectoryInfo pluginDirectory) { AllowGeneratingNewTranslations = false; AllowFallback = false; DefaultAllowFallback = false; _pluginDirectory = pluginDirectory; } public TextTranslationCache(string pluginDirectory) { AllowGeneratingNewTranslations = false; AllowFallback = false; DefaultAllowFallback = false; _pluginDirectory = new DirectoryInfo(Path.Combine(Path.Combine(Settings.TranslationsPath, "plugins"), pluginDirectory)); } private IEnumerable GetTranslationFiles() { return from x in (from x in Directory.GetFiles(_pluginDirectory?.FullName ?? Settings.TranslationsPath, "*", SearchOption.AllDirectories) where x.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) || x.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) where !x.EndsWith("resizer.txt", StringComparison.OrdinalIgnoreCase) select new FileInfo(x) into fi select new { IsZipped = fi.FullName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase), FileInfo = fi } into x orderby x.IsZipped descending select x).ThenByDescending(x => x.FileInfo.FullName, StringComparer.OrdinalIgnoreCase) select x.FileInfo.FullName; } internal CompositeTextTranslationCache GetOrCreateCompositeCache(IReadOnlyTextTranslationCache primary) { if (!_compositeCaches.TryGetValue(primary, out var value)) { value = new CompositeTextTranslationCache(primary, this); _compositeCaches[primary] = value; } return value; } public void PruneMainTranslationFile() { XuaLogger.AutoTranslator.Debug("Pruning text translations in main translation file..."); FileInfo fileInfo = new FileInfo(Settings.AutoTranslationsFilePath); using MemoryStream memoryStream = new MemoryStream(); bool flag; using (FileStream inputStream = fileInfo.OpenRead()) { flag = PruneTranslationFile(inputStream, memoryStream); } if (flag) { string text = fileInfo.FullName + "." + DateTime.Now.ToString("yyyyMMddHHmmssfff.bak"); File.Move(fileInfo.FullName, text); using (FileStream fileStream = new FileStream(fileInfo.FullName, FileMode.Create)) { memoryStream.Seek(0L, SeekOrigin.Begin); memoryStream.WriteTo(fileStream); fileStream.Flush(); fileStream.Close(); } XuaLogger.AutoTranslator.Warn("Generated backup translation file: " + text); } } internal void LoadTranslationFiles() { try { AllowFallback = DefaultAllowFallback; if (_pluginDirectory != null) { XuaLogger.AutoTranslator.Debug("--- Loading Plugin Translations (" + _pluginDirectory.Name + ") ---"); } else { XuaLogger.AutoTranslator.Debug("--- Loading Global Translations ---"); } float realtimeSinceStartup = Time.realtimeSinceStartup; lock (_writeToFileSync) { string text = Path.Combine(Settings.TranslationsPath, "plugins"); Directory.CreateDirectory(Settings.TranslationsPath); if (_pluginDirectory != null) { Directory.CreateDirectory(text); Directory.CreateDirectory(_pluginDirectory.FullName); } else { Directory.CreateDirectory(Path.GetDirectoryName(Settings.AutoTranslationsFilePath)); } _registeredRegexes.Clear(); _defaultRegexes.Clear(); _translations.Clear(); _reverseTranslations.Clear(); _partialTranslations.Clear(); _tokenTranslations.Clear(); _reverseTokenTranslations.Clear(); _registeredSplitterRegexes.Clear(); _splitterRegexes.Clear(); _scopedTranslations.Clear(); _failedRegexLookups.Clear(); string fullName = new FileInfo(Settings.AutoTranslationsFilePath).FullName; string fullName2 = new FileInfo(Settings.SubstitutionFilePath).FullName; string fullName3 = new FileInfo(Settings.PreprocessorsFilePath).FullName; string fullName4 = new FileInfo(Settings.PostprocessorsFilePath).FullName; if (_pluginDirectory == null) { LoadTranslationsInFile(fullName, isOutputFile: true, isLoad: true, AddTranslationSplitterRegex, AddTranslationRegex, AddTranslation); } foreach (string item in GetTranslationFiles().Except(new string[4] { fullName, fullName2, fullName3, fullName4 }, StringComparer.OrdinalIgnoreCase)) { try { if (_pluginDirectory != null || !item.StartsWith(text, StringComparison.OrdinalIgnoreCase)) { LoadTranslationsInFile(item, isOutputFile: false, isLoad: true, AddTranslationSplitterRegex, AddTranslationRegex, AddTranslation); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations in file: " + item); } } } foreach (StreamTranslationPackage streamPackage in _streamPackages) { try { Stream readableStream = streamPackage.GetReadableStream(); if (readableStream.CanSeek) { readableStream.Seek(0L, SeekOrigin.Begin); } LoadTranslationsInStream(readableStream, streamPackage.Name, isOutputFile: false, isLoad: true, AddTranslationSplitterRegex, AddTranslationRegex, AddTranslation); } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while loading translations in stream translation package: " + streamPackage.Name); } } foreach (KeyValuePairTranslationPackage kvpPackage in _kvpPackages) { try { IEnumerable> iterableEntries = kvpPackage.GetIterableEntries(); LoadTranslationsInKeyValuePairs(iterableEntries, kvpPackage.Name); } catch (Exception ex3) { XuaLogger.AutoTranslator.Error(ex3, "An error occurred while loading translations in KVP translation package: " + kvpPackage.Name); } } float realtimeSinceStartup2 = Time.realtimeSinceStartup; XuaLogger.AutoTranslator.Debug($"Loaded translation text files (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); realtimeSinceStartup = Time.realtimeSinceStartup; foreach (KeyValuePair item2 in _translations.ToList()) { UntranslatedText untranslatedText = new UntranslatedText(item2.Key, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); UntranslatedText untranslatedText2 = new UntranslatedText(item2.Value, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.ToLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (untranslatedText.Original_Text_ExternallyTrimmed != item2.Key && !HasTranslated(untranslatedText.Original_Text_ExternallyTrimmed, -1, checkAll: false)) { AddTranslation(untranslatedText.Original_Text_ExternallyTrimmed, untranslatedText2.Original_Text_ExternallyTrimmed, -1); } if (untranslatedText.Original_Text_ExternallyTrimmed != untranslatedText.Original_Text_FullyTrimmed && !HasTranslated(untranslatedText.Original_Text_FullyTrimmed, -1, checkAll: false)) { AddTranslation(untranslatedText.Original_Text_FullyTrimmed, untranslatedText2.Original_Text_FullyTrimmed, -1); } } foreach (KeyValuePair item3 in _scopedTranslations.ToList()) { int key3 = item3.Key; foreach (KeyValuePair item4 in item3.Value.Translations.ToList()) { UntranslatedText untranslatedText3 = new UntranslatedText(item4.Key, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); UntranslatedText untranslatedText4 = new UntranslatedText(item4.Value, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.ToLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (untranslatedText3.Original_Text_ExternallyTrimmed != item4.Key && !HasTranslated(untranslatedText3.Original_Text_ExternallyTrimmed, key3, checkAll: false)) { AddTranslation(untranslatedText3.Original_Text_ExternallyTrimmed, untranslatedText4.Original_Text_ExternallyTrimmed, key3); } if (untranslatedText3.Original_Text_ExternallyTrimmed != untranslatedText3.Original_Text_FullyTrimmed && !HasTranslated(untranslatedText3.Original_Text_FullyTrimmed, key3, checkAll: false)) { AddTranslation(untranslatedText3.Original_Text_FullyTrimmed, untranslatedText4.Original_Text_FullyTrimmed, key3); } } } XuaLogger.AutoTranslator.Debug($"Created variation translations (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); realtimeSinceStartup2 = Time.realtimeSinceStartup; if (Settings.GeneratePartialTranslations) { realtimeSinceStartup = Time.realtimeSinceStartup; foreach (KeyValuePair item5 in _translations.ToList()) { CreatePartialTranslationsFor(item5.Key, item5.Value); } XuaLogger.AutoTranslator.Debug($"Created partial translations (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); realtimeSinceStartup2 = Time.realtimeSinceStartup; } RichTextParser richTextParser = new RichTextParser(); realtimeSinceStartup = Time.realtimeSinceStartup; foreach (KeyValuePair item6 in _translations.ToList()) { ParserResult parserResult = richTextParser.Parse(item6.Key, -1); if (parserResult == null) { continue; } ParserResult parserResult2 = richTextParser.Parse(item6.Value, -1); if (parserResult2 == null || parserResult.Arguments.Count != parserResult2.Arguments.Count) { continue; } foreach (ArgumentedUntranslatedTextInfo argument in parserResult.Arguments) { string key2 = argument.Key; string untranslatedText5 = argument.Info.UntranslatedText; ArgumentedUntranslatedTextInfo argumentedUntranslatedTextInfo = parserResult2.Arguments.FirstOrDefault((ArgumentedUntranslatedTextInfo x) => x.Key == key2); if (argumentedUntranslatedTextInfo != null) { AddTokenTranslation(untranslatedText5, argumentedUntranslatedTextInfo.Info.UntranslatedText, -1); } } } foreach (KeyValuePair item7 in _scopedTranslations.ToList()) { int key4 = item7.Key; foreach (KeyValuePair item8 in item7.Value.Translations.ToList()) { ParserResult parserResult3 = richTextParser.Parse(item8.Key, key4); if (parserResult3 == null) { continue; } ParserResult parserResult4 = richTextParser.Parse(item8.Value, key4); if (parserResult4 == null || parserResult3.Arguments.Count != parserResult4.Arguments.Count) { continue; } foreach (ArgumentedUntranslatedTextInfo argument2 in parserResult3.Arguments) { string key = argument2.Key; string untranslatedText6 = argument2.Info.UntranslatedText; ArgumentedUntranslatedTextInfo argumentedUntranslatedTextInfo2 = parserResult4.Arguments.FirstOrDefault((ArgumentedUntranslatedTextInfo x) => x.Key == key); if (argumentedUntranslatedTextInfo2 != null) { AddTokenTranslation(untranslatedText6, argumentedUntranslatedTextInfo2.Info.UntranslatedText, key4); } } } } XuaLogger.AutoTranslator.Debug($"Created token translations (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); realtimeSinceStartup2 = Time.realtimeSinceStartup; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Translations generated: {_translations.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Regex translations generated: {_defaultRegexes.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Regex splitters generated: {_splitterRegexes.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Token translations generated: {_tokenTranslations.Count}"); } if (Settings.GeneratePartialTranslations) { XuaLogger.AutoTranslator.Debug($"Partial translations generated: {_partialTranslations.Count}"); } foreach (KeyValuePair item9 in _scopedTranslations.OrderBy((KeyValuePair x) => x.Key)) { int key5 = item9.Key; TranslationDictionaries value = item9.Value; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Scene {key5} translations generated: {value.Translations.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Scene {key5} regex translations generated: {value.DefaultRegexes.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Scene {key5} regex splitter generated: {value.SplitterRegexes.Count}"); } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug($"Scene {key5} token translations generated: {value.TokenTranslations.Count}"); } } } catch (Exception ex4) { XuaLogger.AutoTranslator.Error(ex4, "An error occurred while loading translations."); } } private void CreatePartialTranslationsFor(string originalText, string translatedText) { List list = Tokenify(originalText); List list2 = Tokenify(translatedText); double num = (double)list2.Count / (double)list.Count; int num2 = 0; string text = string.Empty; string text2 = string.Empty; for (int i = 0; i < list.Count; i++) { TranslationCharacterToken translationCharacterToken = list[i]; text = ((!translationCharacterToken.IsVariable) ? (text + translationCharacterToken.Character) : (text + "{{" + translationCharacterToken.Character + "}}")); int num3 = (int)Math.Round((double)(i + 1) * num, 0, MidpointRounding.AwayFromZero); for (int j = num2; j < num3; j++) { TranslationCharacterToken translationCharacterToken2 = list2[j]; text2 = ((!translationCharacterToken2.IsVariable) ? (text2 + translationCharacterToken2.Character) : (text2 + "{{" + translationCharacterToken2.Character + "}}")); } num2 = num3; if (!HasTranslated(text, -1, checkAll: false)) { AddTranslation(text, text2, -1); _partialTranslations.Add(text); } } } private static List Tokenify(string text) { List list = new List(text.Length); for (int i = 0; i < text.Length; i++) { char c = text[i]; if (c == '{' && text.Length > i + 4 && text[i + 1] == '{' && text[i + 3] == '}' && text[i + 4] == '}') { c = text[i + 2]; list.Add(new TranslationCharacterToken(c, isVariable: true)); i += 4; } else { list.Add(new TranslationCharacterToken(c, isVariable: false)); } } return list; } private bool PruneTranslationFile(Stream inputStream, Stream outputStream) { HashSet registerdRegexes = new HashSet(); List regexes = new List(); Action addTranslationRegex = delegate(RegexTranslation regex, int level) { if (level == -1 && !registerdRegexes.Contains(regex.Original)) { registerdRegexes.Add(regex.Original); regexes.Add(regex); } }; string value = Path.Combine(Settings.TranslationsPath, "plugins"); string fullName = new FileInfo(Settings.AutoTranslationsFilePath).FullName; string fullName2 = new FileInfo(Settings.SubstitutionFilePath).FullName; string fullName3 = new FileInfo(Settings.PreprocessorsFilePath).FullName; string fullName4 = new FileInfo(Settings.PostprocessorsFilePath).FullName; foreach (string item in GetTranslationFiles().Except(new string[4] { fullName, fullName2, fullName3, fullName4 }, StringComparer.OrdinalIgnoreCase)) { try { if (_pluginDirectory != null || !item.StartsWith(value, StringComparison.OrdinalIgnoreCase)) { LoadTranslationsInFile(item, isOutputFile: false, isLoad: false, null, addTranslationRegex, null); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations in file: " + item); } } bool result = false; StreamReader streamReader = new StreamReader(inputStream, Encoding.UTF8); StreamWriter streamWriter = new StreamWriter(outputStream, Encoding.UTF8); string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { string[] array2 = TextHelper.ReadTranslationLineAndDecode(text); if (array2 == null) { continue; } string key = array2[0]; string text2 = array2[1]; if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(text2) && !key.StartsWith("sr:") && !key.StartsWith("r:")) { if (!regexes.Any((RegexTranslation x) => x.CompiledRegex.IsMatch(key))) { streamWriter.WriteLine(TextHelper.Encode(key) + "=" + TextHelper.Encode(text2)); continue; } XuaLogger.AutoTranslator.Warn("Pruned translation: " + text); result = true; } } streamWriter.Flush(); return result; } private void LoadTranslationsInStream(Stream stream, string fullFileName, bool isOutputFile, bool isLoad, Action addTranslationSplitterRegex, Action addTranslationRegex, Action addTranslation) { if (!Settings.EnableSilentMode && isLoad) { XuaLogger.AutoTranslator.Debug("Loading texts: " + fullFileName + "."); } StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); TranslationFileLoadingContext translationFileLoadingContext = new TranslationFileLoadingContext(); string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { try { if (isOutputFile) { goto IL_00a9; } TranslationFileDirective translationFileDirective = TranslationFileDirective.Create(text); if (translationFileDirective == null) { goto IL_00a9; } translationFileLoadingContext.Apply(translationFileDirective); if (!Settings.EnableSilentMode && isLoad) { XuaLogger.AutoTranslator.Debug("Directive in file: " + fullFileName + ": " + translationFileDirective.ToString()); } goto end_IL_005f; IL_00a9: if (!translationFileLoadingContext.IsApplicable()) { continue; } string[] array2 = TextHelper.ReadTranslationLineAndDecode(text); if (array2 == null) { continue; } string text2 = array2[0]; string text3 = array2[1]; if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(text3)) { continue; } if (text2.StartsWith("sr:")) { try { RegexTranslationSplitter arg = new RegexTranslationSplitter(text2, text3); HashSet levels = translationFileLoadingContext.GetLevels(); if (levels.Count == 0) { addTranslationSplitterRegex?.Invoke(arg, -1); continue; } foreach (int item in levels) { addTranslationSplitterRegex?.Invoke(arg, item); } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while constructing regex translation splitter: '" + text + "'."); } continue; } if (text2.StartsWith("r:")) { try { RegexTranslation arg2 = new RegexTranslation(text2, text3); HashSet levels2 = translationFileLoadingContext.GetLevels(); if (levels2.Count == 0) { addTranslationRegex?.Invoke(arg2, -1); continue; } foreach (int item2 in levels2) { addTranslationRegex?.Invoke(arg2, item2); } } catch (Exception ex2) { XuaLogger.AutoTranslator.Warn(ex2, "An error occurred while constructing regex translation: '" + text + "'."); } continue; } HashSet levels3 = translationFileLoadingContext.GetLevels(); if (levels3.Count == 0) { addTranslation?.Invoke(text2, text3, -1); continue; } foreach (int item3 in levels3) { addTranslation?.Invoke(text2, text3, item3); } end_IL_005f:; } catch (Exception ex3) { XuaLogger.AutoTranslator.Warn(ex3, "An error occurred while reading translation: '" + text + "'."); } } if (isLoad) { AllowFallback = AllowFallback || translationFileLoadingContext.IsEnabled("fallback"); } } private void LoadTranslationsInKeyValuePairs(IEnumerable> pairs, string fullFileName) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Loading texts: " + fullFileName + "."); } foreach (KeyValuePair pair in pairs) { string key = pair.Key; string value = pair.Value; if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) { continue; } if (key.StartsWith("sr:")) { try { RegexTranslationSplitter regex = new RegexTranslationSplitter(key, value); AddTranslationSplitterRegex(regex, -1); } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while constructing regex translation splitter: '" + key + "=" + value + "'."); } } else if (key.StartsWith("r:")) { try { RegexTranslation regex2 = new RegexTranslation(key, value); AddTranslationRegex(regex2, -1); } catch (Exception ex2) { XuaLogger.AutoTranslator.Warn(ex2, "An error occurred while constructing regex translation: '" + key + "=" + value + "'."); } } else { AddTranslation(key, value, -1); } } } private void LoadTranslationsInFile(string fullFileName, bool isOutputFile, bool isLoad, Action addTranslationSplitterRegex, Action addTranslationRegex, Action addTranslation) { bool flag = File.Exists(fullFileName); if (!flag || !flag) { return; } using FileStream fileStream = File.OpenRead(fullFileName); if (fullFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { ZipFile zipFile = new ZipFile(fileStream); foreach (ZipEntry item in zipFile.GetEntries().OrderByDescending((ZipEntry x) => x.Name, StringComparer.OrdinalIgnoreCase)) { if (item.IsFile && item.Name.EndsWith(".txt", StringComparison.OrdinalIgnoreCase) && !item.Name.EndsWith("resizer.txt", StringComparison.OrdinalIgnoreCase)) { Stream inputStream = zipFile.GetInputStream(item); char directorySeparatorChar = Path.DirectorySeparatorChar; LoadTranslationsInStream(inputStream, fullFileName + directorySeparatorChar + item.Name, isOutputFile, isLoad, addTranslationSplitterRegex, addTranslationRegex, addTranslation); } } zipFile.Close(); } else { LoadTranslationsInStream(fileStream, fullFileName, isOutputFile, isLoad, addTranslationSplitterRegex, addTranslationRegex, addTranslation); } } private void LoadStaticTranslations() { if (!Settings.UseStaticTranslations || !(Settings.FromLanguage == Settings.DefaultFromLanguage) || !(Settings.Language == Settings.DefaultLanguage)) { return; } string[] array = Resources.StaticTranslations.Split(new string[1] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = TextHelper.ReadTranslationLineAndDecode(array[i]); if (array2 != null) { string text = array2[0]; string value = array2[1]; if (!string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(value)) { _staticTranslations[text] = value; } } } } internal void RegisterPackage(StreamTranslationPackage package) { _streamPackages.Add(package); } internal void RegisterPackage(KeyValuePairTranslationPackage package) { _kvpPackages.Add(package); } private void SaveNewTranslationsToDisk() { if (_newTranslations.Count <= 0) { return; } lock (_writeToFileSync) { if (_newTranslations.Count <= 0) { return; } _fileWatcher?.Disable(); try { using (FileStream stream = File.Open(Settings.AutoTranslationsFilePath, FileMode.Append, FileAccess.Write)) { using StreamWriter streamWriter = new StreamWriter(stream, Encoding.UTF8); foreach (KeyValuePair newTranslation in _newTranslations) { streamWriter.WriteLine(TextHelper.Encode(newTranslation.Key) + "=" + TextHelper.Encode(newTranslation.Value)); } streamWriter.Flush(); } _newTranslations.Clear(); } finally { _fileWatcher?.Enable(); } } } private void AddTranslationSplitterRegex(RegexTranslationSplitter regex, int scope) { if (scope != -1) { if (!_scopedTranslations.TryGetValue(scope, out var value)) { value = new TranslationDictionaries(); _scopedTranslations.Add(scope, value); } if (!value.RegisteredSplitterRegexes.Contains(regex.Original)) { value.RegisteredSplitterRegexes.Add(regex.Original); value.SplitterRegexes.Add(regex); } } else if (!_registeredSplitterRegexes.Contains(regex.Original)) { _registeredSplitterRegexes.Add(regex.Original); _splitterRegexes.Add(regex); } } private void AddTranslationRegex(RegexTranslation regex, int scope) { if (scope != -1) { if (!_scopedTranslations.TryGetValue(scope, out var value)) { value = new TranslationDictionaries(); _scopedTranslations.Add(scope, value); } if (!value.RegisteredRegexes.Contains(regex.Original)) { value.RegisteredRegexes.Add(regex.Original); value.DefaultRegexes.Add(regex); } } else if (!_registeredRegexes.Contains(regex.Original)) { _registeredRegexes.Add(regex.Original); _defaultRegexes.Add(regex); } } private bool HasTranslated(string key, int scope, bool checkAll) { if (checkAll) { if (!_translations.ContainsKey(key)) { if (scope != -1 && _scopedTranslations.TryGetValue(scope, out var value)) { return value.Translations.ContainsKey(key); } return false; } return true; } if (scope != -1) { if (scope != -1 && _scopedTranslations.TryGetValue(scope, out var value2)) { return value2.Translations.ContainsKey(key); } return false; } return _translations.ContainsKey(key); } private bool IsTranslation(string translation, int scope) { if (HasTranslated(translation, scope, checkAll: true)) { return false; } if (_reverseTranslations.ContainsKey(translation)) { return true; } if (scope != -1 && _scopedTranslations.TryGetValue(scope, out var value) && value.ReverseTranslations.ContainsKey(translation)) { return true; } return false; } private bool IsTokenTranslation(string translation, int scope) { if (_reverseTokenTranslations.ContainsKey(translation)) { return true; } if (scope != -1 && _scopedTranslations.TryGetValue(scope, out var value) && value.ReverseTokenTranslations.ContainsKey(translation)) { return true; } return false; } private void AddTranslation(string key, string value, int scope) { if (key == null || value == null) { return; } if (scope != -1) { if (!_scopedTranslations.TryGetValue(scope, out var value2)) { value2 = new TranslationDictionaries(); _scopedTranslations.Add(scope, value2); } value2.Translations[key] = value; value2.ReverseTranslations[value] = key; } else { _translations[key] = value; _reverseTranslations[value] = key; } } private void AddTokenTranslation(string key, string value, int scope) { if (key == null || value == null) { return; } if (scope != -1) { if (!_scopedTranslations.TryGetValue(scope, out var value2)) { value2 = new TranslationDictionaries(); _scopedTranslations.Add(scope, value2); } value2.TokenTranslations[key] = value; value2.ReverseTokenTranslations[value] = key; } else { _tokenTranslations[key] = value; _reverseTokenTranslations[value] = key; } } private void QueueNewTranslationForDisk(string key, string value) { lock (_writeToFileSync) { _newTranslations[key] = value; } } internal void AddTranslationToCache(string key, string value, bool persistToDisk, TranslationType type, int scope) { if ((type & TranslationType.Token) == TranslationType.Token && !persistToDisk) { AddTokenTranslation(key, value, scope); } if (!((type & TranslationType.Full) == TranslationType.Full || persistToDisk) || HasTranslated(key, scope, checkAll: false)) { return; } AddTranslation(key, value, scope); UntranslatedText untranslatedText = new UntranslatedText(key, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); UntranslatedText untranslatedText2 = new UntranslatedText(value, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.ToLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (untranslatedText.Original_Text_ExternallyTrimmed != key && !HasTranslated(untranslatedText.Original_Text_ExternallyTrimmed, scope, checkAll: false)) { AddTranslation(untranslatedText.Original_Text_ExternallyTrimmed, untranslatedText2.Original_Text_ExternallyTrimmed, scope); } if (untranslatedText.Original_Text_ExternallyTrimmed != untranslatedText.Original_Text_FullyTrimmed && !HasTranslated(untranslatedText.Original_Text_FullyTrimmed, scope, checkAll: false)) { AddTranslation(untranslatedText.Original_Text_FullyTrimmed, untranslatedText2.Original_Text_FullyTrimmed, scope); } if (persistToDisk) { if (scope != -1) { XuaLogger.AutoTranslator.Error("Stored scoped translation to cache, even though this is not supported!"); } QueueNewTranslationForDisk(key, value); } } public bool TryGetTranslationSplitter(string text, int scope, out Match match, out RegexTranslationSplitter splitter) { if (scope != -1 && _scopedTranslations.TryGetValue(scope, out var value) && value.SplitterRegexes.Count > 0) { for (int num = value.SplitterRegexes.Count - 1; num > -1; num--) { RegexTranslationSplitter regexTranslationSplitter = value.SplitterRegexes[num]; try { match = regexTranslationSplitter.CompiledRegex.Match(text); splitter = regexTranslationSplitter; if (match.Success) { return true; } } catch (Exception ex) { value.SplitterRegexes.RemoveAt(num); XuaLogger.AutoTranslator.Error(ex, "Failed while attempting to replace or match text of splitter regex '" + regexTranslationSplitter.Original + "'. Removing that regex from the cache."); } } } for (int num2 = _splitterRegexes.Count - 1; num2 > -1; num2--) { RegexTranslationSplitter regexTranslationSplitter2 = _splitterRegexes[num2]; try { match = regexTranslationSplitter2.CompiledRegex.Match(text); splitter = regexTranslationSplitter2; if (match.Success) { return true; } } catch (Exception ex2) { _splitterRegexes.RemoveAt(num2); XuaLogger.AutoTranslator.Error(ex2, "Failed while attempting to replace or match text of splitter regex '" + regexTranslationSplitter2.Original + "'. Removing that regex from the cache."); } } match = null; splitter = null; return false; } public bool TryGetTranslation(UntranslatedText key, bool allowRegex, bool allowToken, int scope, out string value) { string text = null; string text2 = null; string text3 = null; string text4 = null; TranslationDictionaries value2 = null; bool flag; if (scope != -1 && _scopedTranslations.TryGetValue(scope, out value2)) { if (allowToken && value2.TokenTranslations.Count > 0) { if (key.IsTemplated && !key.IsFromSpammingComponent) { string key2 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); flag = value2.TokenTranslations.TryGetValue(key2, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { key2 = text2 ?? (text2 = key.Untemplate(key.TemplatedOriginal_Text_InternallyTrimmed)); flag = value2.TokenTranslations.TryGetValue(key2, out value); if (flag) { return flag; } } } flag = value2.TokenTranslations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = value2.TokenTranslations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { return flag; } } } if (key.IsTemplated && !key.IsFromSpammingComponent && value2.Translations.Count > 0) { string key2 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); flag = value2.Translations.TryGetValue(key2, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { key2 = text3 ?? (text3 = key.Untemplate(key.TemplatedOriginal_Text_ExternallyTrimmed)); flag = value2.Translations.TryGetValue(key2, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c1): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, persistToDisk: false, TranslationType.Full, scope); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { key2 = text2 ?? (text2 = key.Untemplate(key.TemplatedOriginal_Text_InternallyTrimmed)); flag = value2.Translations.TryGetValue(key2, out value); if (flag) { string text5 = value; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c2): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, persistToDisk: false, TranslationType.Full, scope); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { key2 = text4 ?? (text4 = key.Untemplate(key.TemplatedOriginal_Text_FullyTrimmed)); flag = value2.Translations.TryGetValue(key2, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c3): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, persistToDisk: false, TranslationType.Full, scope); value = text5; return flag; } } } if (value2.Translations.Count > 0) { flag = value2.Translations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { flag = value2.Translations.TryGetValue(key.TemplatedOriginal_Text_ExternallyTrimmed, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c7): '" + key.TemplatedOriginal_Text + "' => '" + text5 + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, text5, persistToDisk: false, TranslationType.Full, scope); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = value2.Translations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c8): '" + key.TemplatedOriginal_Text + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, persistToDisk: false, TranslationType.Full, scope); return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { flag = value2.Translations.TryGetValue(key.TemplatedOriginal_Text_FullyTrimmed, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c9): '" + key.TemplatedOriginal_Text + "' => '" + text5 + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, text5, persistToDisk: false, TranslationType.Full, scope); value = text5; return flag; } } } } if (allowToken && _tokenTranslations.Count > 0) { if (key.IsTemplated && !key.IsFromSpammingComponent) { string key2 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); flag = _tokenTranslations.TryGetValue(key2, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { key2 = text2 ?? (text2 = key.Untemplate(key.TemplatedOriginal_Text_InternallyTrimmed)); flag = _tokenTranslations.TryGetValue(key2, out value); if (flag) { return flag; } } } flag = _tokenTranslations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = _tokenTranslations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { return flag; } } } if (key.IsTemplated && !key.IsFromSpammingComponent) { string key2 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); flag = _translations.TryGetValue(key2, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { key2 = text3 ?? (text3 = key.Untemplate(key.TemplatedOriginal_Text_ExternallyTrimmed)); flag = _translations.TryGetValue(key2, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c4): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { key2 = text2 ?? (text2 = key.Untemplate(key.TemplatedOriginal_Text_InternallyTrimmed)); flag = _translations.TryGetValue(key2, out value); if (flag) { string text5 = value; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c5): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { key2 = text4 ?? (text4 = key.Untemplate(key.TemplatedOriginal_Text_FullyTrimmed)); flag = _translations.TryGetValue(key2, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; string text6 = text ?? (text = key.Untemplate(key.TemplatedOriginal_Text)); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c6): '" + text6 + "' => '" + text5 + "'"); } AddTranslationToCache(text6, text5, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); value = text5; return flag; } } } flag = _translations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_ExternallyTrimmed, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c10): '" + key.TemplatedOriginal_Text + "' => '" + text5 + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, text5, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); value = text5; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c11): '" + key.TemplatedOriginal_Text + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_FullyTrimmed, out value); if (flag) { string text5 = key.LeadingWhitespace + value + key.TrailingWhitespace; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Whitespace difference (c12): '" + key.TemplatedOriginal_Text + "' => '" + text5 + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, text5, Settings.CacheWhitespaceDifferences, TranslationType.Full, -1); value = text5; return flag; } } if (allowRegex) { if (value2 != null && value2.DefaultRegexes.Count > 0 && !value2.FailedRegexLookups.Contains(key.TemplatedOriginal_Text)) { for (int num = value2.DefaultRegexes.Count - 1; num > -1; num--) { RegexTranslation regexTranslation = value2.DefaultRegexes[num]; try { Match match = regexTranslation.CompiledRegex.Match(key.TemplatedOriginal_Text); if (match.Success) { value = match.Result(regexTranslation.Translation); value = RomanizationHelper.PostProcess(value, Settings.RegexPostProcessing); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Regex lookup: '" + key.TemplatedOriginal_Text + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, persistToDisk: false, TranslationType.Full, scope); return true; } } catch (Exception ex) { value2.DefaultRegexes.RemoveAt(num); XuaLogger.AutoTranslator.Error(ex, "Failed while attempting to replace or match text of regex '" + regexTranslation.Original + "'. Removing that regex from the cache."); } } if (value2.FailedRegexLookups.Add(key.TemplatedOriginal_Text) && value2.FailedRegexLookups.Count > 10000) { value2.FailedRegexLookups = new HashSet(); } } if (!_failedRegexLookups.Contains(key.TemplatedOriginal_Text)) { for (int num2 = _defaultRegexes.Count - 1; num2 > -1; num2--) { RegexTranslation regexTranslation2 = _defaultRegexes[num2]; try { Match match2 = regexTranslation2.CompiledRegex.Match(key.TemplatedOriginal_Text); if (match2.Success) { value = match2.Result(regexTranslation2.Translation); value = RomanizationHelper.PostProcess(value, Settings.RegexPostProcessing); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Regex lookup: '" + key.TemplatedOriginal_Text + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, Settings.CacheRegexLookups, TranslationType.Full, -1); return true; } } catch (Exception ex2) { _defaultRegexes.RemoveAt(num2); XuaLogger.AutoTranslator.Error(ex2, "Failed while attempting to replace or match text of regex '" + regexTranslation2.Original + "'. Removing that regex from the cache."); } } if (_failedRegexLookups.Add(key.TemplatedOriginal_Text) && _failedRegexLookups.Count > 10000) { _failedRegexLookups = new HashSet(); } } } if (_staticTranslations.Count > 0) { flag = _staticTranslations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Static lookup: '" + key.TemplatedOriginal_Text + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, persistToDisk: true, TranslationType.Full, -1); return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = _staticTranslations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Static lookup: '" + key.TemplatedOriginal_Text_InternallyTrimmed + "' => '" + value + "'"); } AddTranslationToCache(key.TemplatedOriginal_Text, value, persistToDisk: true, TranslationType.Full, -1); return flag; } } } return flag; } internal bool TryGetReverseTranslation(string value, int scope, out string key) { if (scope == -1 || !_scopedTranslations.TryGetValue(scope, out var value2) || !value2.ReverseTranslations.TryGetValue(value, out key)) { return _reverseTranslations.TryGetValue(value, out key); } return true; } public bool IsTranslatable(string text, bool isToken, int scope) { bool flag = !IsTranslation(text, scope); if (isToken && flag) { flag = !IsTokenTranslation(text, scope); } return flag; } public bool IsPartial(string text, int scope) { return _partialTranslations.Contains(text); } private void Dispose(bool disposing) { if (!disposedValue) { if (disposing) { _fileWatcher?.Dispose(); _fileWatcher = null; } disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } internal sealed class TextTranslationInfo { private Action _unresize; private Action _unfont; private bool _hasCheckedTypeWriter; private MonoBehaviour _typewriter; private float? _alteredLineSpacing; private int? _alteredFontSize; private bool _initialized; private HashSet _redirectedTranslations; private static readonly WeakDictionary _FontMaterialCopies = new WeakDictionary(); public ITextComponentManipulator TextManipulator { get; set; } public string OriginalText { get; set; } public string TranslatedText { get; set; } public bool IsTranslated { get; set; } public bool IsCurrentlySettingText { get; set; } public bool IsStabilizingText { get; set; } public bool IsKnownTextComponent { get; set; } public bool SupportsStabilization { get; set; } public bool ShouldIgnore { get; set; } public HashSet RedirectedTranslations => _redirectedTranslations ?? (_redirectedTranslations = new HashSet()); public IReadOnlyTextTranslationCache TextCache { get; set; } public void Initialize(object ui) { if (!_initialized) { _initialized = true; IsKnownTextComponent = ui.IsKnownTextType(); SupportsStabilization = ui.SupportsStabilization(); ShouldIgnore = ui.ShouldIgnoreTextComponent(); TextManipulator = ui.GetTextManipulator(); } } public void Reset(string newText) { IsTranslated = false; TranslatedText = null; OriginalText = newText; } public void SetTranslatedText(string translatedText) { IsTranslated = true; TranslatedText = translatedText; } public void ResetScrollIn(object ui) { if (!_hasCheckedTypeWriter) { _hasCheckedTypeWriter = true; if (UnityTypes.Typewriter != null) { Component val = (Component)((ui is Component) ? ui : null); MonoBehaviour typewriter = default(MonoBehaviour); if (ui != null && ObjectExtensions.TryCastTo((object)val.GetComponent(UnityTypes.Typewriter.UnityType), ref typewriter)) { _typewriter = typewriter; } } } if ((Object)(object)_typewriter != (Object)null) { AccessToolsShim.Method(UnityTypes.Typewriter.ClrType, "OnEnable", new Type[0])?.Invoke(_typewriter, null); } } public void ChangeFont(object ui) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown if (ui == null) { return; } Type unityType = ObjectExtensions.GetUnityType(ui); if (UnityTypes.Text != null && UnityTypes.Text.IsAssignableFrom(unityType)) { if (string.IsNullOrEmpty(Settings.OverrideFont)) { return; } CachedProperty Text_fontProperty = Text_Properties.Font; Font previousFont2 = (Font)Text_fontProperty.Get(ui); CachedProperty fontSize = Font_Properties.FontSize; if ((Object)(object)previousFont2 == (Object)null) { return; } Font orCreate = FontCache.GetOrCreate((int)((fontSize != null) ? fontSize.Get((object)previousFont2) : null)); if (!((Object)(object)orCreate == (Object)null) && !UnityObjectReferenceComparer.Default.Equals((object)orCreate, (object)previousFont2)) { Text_fontProperty.Set(ui, (object)orCreate); _unfont = delegate(object obj) { Text_fontProperty.Set(obj, (object)previousFont2); }; } } else { if ((UnityTypes.TextMeshPro == null || !UnityTypes.TextMeshPro.IsAssignableFrom(unityType)) && (UnityTypes.TextMeshProUGUI == null || !UnityTypes.TextMeshProUGUI.IsAssignableFrom(unityType))) { return; } if (string.IsNullOrEmpty(Settings.OverrideFontTextMeshPro)) { return; } Type type = ui.GetType(); CachedProperty fontProperty = ReflectionCache.CachedProperty(type, "font"); object previousFont = fontProperty.Get(ui); if (previousFont == null) { return; } object orCreateOverrideFontTextMeshPro = FontCache.GetOrCreateOverrideFontTextMeshPro(); if (orCreateOverrideFontTextMeshPro == null || UnityObjectReferenceComparer.Default.Equals(orCreateOverrideFontTextMeshPro, previousFont)) { return; } CachedProperty fontMaterialProperty = ReflectionCache.CachedProperty(type, "fontSharedMaterial"); Material oldMaterial = default(Material); ref Material reference = ref oldMaterial; object obj2 = fontMaterialProperty.Get(ui); reference = (Material)((obj2 is Material) ? obj2 : null); fontProperty.Set(ui, orCreateOverrideFontTextMeshPro); object obj3 = fontMaterialProperty.Get(ui); Material val = (Material)((obj3 is Material) ? obj3 : null); if ((Object)(object)oldMaterial != (Object)null && (Object)(object)val != (Object)null) { Material val2 = default(Material); if (!((BaseDictionary)(object)_FontMaterialCopies).TryGetValue(oldMaterial, ref val2)) { Material val4 = (((BaseDictionary)(object)_FontMaterialCopies)[oldMaterial] = Object.Instantiate(oldMaterial)); val2 = val4; Object val5 = Object.Instantiate((Object)((ui is Object) ? ui : null)); fontProperty.Set((object)val5, previousFont); fontMaterialProperty.Set((object)val5, (object)oldMaterial); val2.SetTexture("_MainTex", val.GetTexture("_MainTex")); val2.SetFloat("_TextureHeight", val.GetFloat("_TextureHeight")); val2.SetFloat("_TextureWidth", val.GetFloat("_TextureWidth")); val2.SetFloat("_GradientScale", val.GetFloat("_GradientScale")); } fontMaterialProperty.Set(ui, (object)val2); } _unfont = delegate(object obj) { fontProperty.Set(obj, previousFont); fontMaterialProperty.Set(obj, (object)oldMaterial); }; } } public void UnchangeFont(object ui) { if (ui != null) { _unfont?.Invoke(ui); _unfont = null; } } private static float GetComponentWidth(Component component) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) RectTransform val = default(RectTransform); if (ObjectExtensions.TryCastTo((object)component.transform, ref val)) { Rect rect = val.rect; return ((Rect)(ref rect)).width; } return 0f; } public void ResizeUI(object ui, UIResizeCache cache) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Expected O, but got Unknown //IL_0912: Unknown result type (might be due to invalid IL or missing references) //IL_0919: Expected O, but got Unknown //IL_0772: Unknown result type (might be due to invalid IL or missing references) //IL_0779: Expected O, but got Unknown if (ui == null) { return; } Type unityType = ObjectExtensions.GetUnityType(ui); if (UnityTypes.Text != null && UnityTypes.Text.IsAssignableFrom(unityType)) { Component val = (Component)ui; if (!Object.op_Implicit((Object)(object)val) || !Object.op_Implicit((Object)(object)val.gameObject)) { return; } float componentWidth = GetComponentWidth(val); int num = Screen.width / 4; bool num2 = componentWidth > (float)num; bool flag = false; bool flag2 = false; bool flag3 = false; bool flag4 = _unresize == null; if (cache.HasAnyResizeCommands) { string[] pathSegments = val.gameObject.GetPathSegments(); int scope = TranslationScopeHelper.GetScope(ui); if (cache.TryGetUIResize(pathSegments, scope, out var result)) { if (result.AutoResizeCommand != null) { object resizeTextForBestFitValue = Text_Properties.ResizeTextForBestFit.Get(ui); if (resizeTextForBestFitValue != null) { CachedProperty resizeTextMinSize = Text_Properties.ResizeTextMinSize; object resizeTextMinSizeValue = ((resizeTextMinSize != null) ? resizeTextMinSize.Get(ui) : null); CachedProperty resizeTextMaxSize = Text_Properties.ResizeTextMaxSize; object resizeTextMaxSizeValue = ((resizeTextMaxSize != null) ? resizeTextMaxSize.Get(ui) : null); double valueOrDefault = result.AutoResizeCommand.GetMinSize().GetValueOrDefault(1.0); if (Text_Properties.ResizeTextMinSize != null) { int num3 = (double.IsNaN(valueOrDefault) ? 1 : ((int)valueOrDefault)); Text_Properties.ResizeTextMinSize.Set(ui, (object)num3); } double? maxSize = result.AutoResizeCommand.GetMaxSize(); if (maxSize.HasValue && Text_Properties.ResizeTextMaxSize != null) { int num4 = (double.IsNaN(maxSize.Value) ? 1 : ((int)maxSize.Value)); CachedProperty resizeTextMaxSize2 = Text_Properties.ResizeTextMaxSize; if (resizeTextMaxSize2 != null) { resizeTextMaxSize2.Set(ui, (object)num4); } } bool flag5 = result.AutoResizeCommand.ShouldAutoResize(); Text_Properties.ResizeTextForBestFit.Set(ui, (object)flag5); if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.ResizeTextForBestFit.Set(g, resizeTextForBestFitValue); }); if (Text_Properties.ResizeTextMinSize != null) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.ResizeTextMinSize.Set(g, resizeTextMinSizeValue); }); } if (maxSize.HasValue && Text_Properties.ResizeTextMaxSize != null) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.ResizeTextMaxSize.Set(g, resizeTextMaxSizeValue); }); } } } } if (result.ResizeCommand != null) { int? currentFontSize4 = (int?)Text_Properties.FontSize.Get(ui); if (currentFontSize4.HasValue && !object.Equals(_alteredFontSize, currentFontSize4)) { int? size = result.ResizeCommand.GetSize(currentFontSize4.Value); if (size.HasValue) { Text_Properties.FontSize.Set(ui, (object)size.Value); _alteredFontSize = size.Value; if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.FontSize.Set(g, (object)currentFontSize4); }); } } } } if (result.LineSpacingCommand != null) { float? lineSpacingValue = (float?)Text_Properties.LineSpacing.Get(ui); if (lineSpacingValue.HasValue && !object.Equals(_alteredLineSpacing, lineSpacingValue)) { float? lineSpacing = result.LineSpacingCommand.GetLineSpacing(lineSpacingValue.Value); if (lineSpacing.HasValue) { flag = true; Text_Properties.LineSpacing.Set(ui, (object)lineSpacing.Value); _alteredLineSpacing = lineSpacing; if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.LineSpacing.Set(g, (object)lineSpacingValue); }); } } } } if (result.HorizontalOverflowCommand != null) { object horizontalOverflowValue = Text_Properties.HorizontalOverflow.Get(ui); if (horizontalOverflowValue != null) { int? mode = result.HorizontalOverflowCommand.GetMode(); if (mode.HasValue) { flag2 = true; Text_Properties.HorizontalOverflow.Set(ui, (object)mode.Value); if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.HorizontalOverflow.Set(g, horizontalOverflowValue); }); } } } } if (result.VerticalOverflowCommand != null) { object verticalOverflowValue = Text_Properties.VerticalOverflow.Get(ui); if (verticalOverflowValue != null) { int? mode2 = result.VerticalOverflowCommand.GetMode(); if (mode2.HasValue) { flag3 = true; Text_Properties.VerticalOverflow.Set(ui, (object)mode2.Value); if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.VerticalOverflow.Set(g, verticalOverflowValue); }); } } } } } } if (!num2 || (Text_Properties.ResizeTextForBestFit != null && (bool)Text_Properties.ResizeTextForBestFit.Get((object)val))) { return; } if (!flag && Settings.ResizeUILineSpacingScale.HasValue && Text_Properties.LineSpacing != null) { object originalLineSpacing = Text_Properties.LineSpacing.Get((object)val); if (!object.Equals(_alteredLineSpacing, originalLineSpacing)) { float num5 = (float)originalLineSpacing * Settings.ResizeUILineSpacingScale.Value; Text_Properties.LineSpacing.Set((object)val, (object)num5); _alteredLineSpacing = num5; if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.LineSpacing.Set(g, originalLineSpacing); }); } } } if (!flag3 && Text_Properties.VerticalOverflow != null) { object originalVerticalOverflow = Text_Properties.VerticalOverflow.Get((object)val); Text_Properties.VerticalOverflow.Set((object)val, (object)1); if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.VerticalOverflow.Set(g, originalVerticalOverflow); }); } } if (flag2 || Text_Properties.HorizontalOverflow == null) { return; } object originalHorizontalOverflow = Text_Properties.HorizontalOverflow.Get((object)val); Text_Properties.HorizontalOverflow.Set((object)val, (object)0); if (flag4) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { Text_Properties.HorizontalOverflow.Set(g, originalHorizontalOverflow); }); } return; } TypeContainer uILabel = UnityTypes.UILabel; if ((object)unityType == ((uILabel != null) ? uILabel.UnityType : null)) { CachedProperty useFloatSpacing = UILabel_Properties.UseFloatSpacing; object useFloatSpacingPropertyValue = ((useFloatSpacing != null) ? useFloatSpacing.Get(ui) : null); CachedProperty spacingX = UILabel_Properties.SpacingX; object spacingXPropertyValue = ((spacingX != null) ? spacingX.Get(ui) : null); CachedProperty multiLine = UILabel_Properties.MultiLine; object multiLinePropertyValue = ((multiLine != null) ? multiLine.Get(ui) : null); CachedProperty overflowMethod = UILabel_Properties.OverflowMethod; object overflowMethodPropertyValue = ((overflowMethod != null) ? overflowMethod.Get(ui) : null); CachedProperty useFloatSpacing2 = UILabel_Properties.UseFloatSpacing; if (useFloatSpacing2 != null) { useFloatSpacing2.Set(ui, (object)false); } CachedProperty spacingX2 = UILabel_Properties.SpacingX; if (spacingX2 != null) { spacingX2.Set(ui, (object)(-1)); } CachedProperty multiLine2 = UILabel_Properties.MultiLine; if (multiLine2 != null) { multiLine2.Set(ui, (object)true); } CachedProperty overflowMethod2 = UILabel_Properties.OverflowMethod; if (overflowMethod2 != null) { overflowMethod2.Set(ui, (object)0); } if (_unresize == null) { _unresize = delegate(object g) { CachedProperty useFloatSpacing3 = UILabel_Properties.UseFloatSpacing; if (useFloatSpacing3 != null) { useFloatSpacing3.Set(g, useFloatSpacingPropertyValue); } CachedProperty spacingX3 = UILabel_Properties.SpacingX; if (spacingX3 != null) { spacingX3.Set(g, spacingXPropertyValue); } CachedProperty multiLine3 = UILabel_Properties.MultiLine; if (multiLine3 != null) { multiLine3.Set(g, multiLinePropertyValue); } CachedProperty overflowMethod3 = UILabel_Properties.OverflowMethod; if (overflowMethod3 != null) { overflowMethod3.Set(g, overflowMethodPropertyValue); } }; } if (!cache.HasAnyResizeCommands) { return; } Component val2 = (Component)ui; if (!Object.op_Implicit((Object)(object)val2) || !Object.op_Implicit((Object)(object)val2.gameObject)) { return; } Type type = ui.GetType(); string[] pathSegments2 = val2.gameObject.GetPathSegments(); int scope2 = TranslationScopeHelper.GetScope(ui); if (!cache.TryGetUIResize(pathSegments2, scope2, out var result2) || result2.ResizeCommand == null) { return; } CachedProperty fontSizeProperty3 = ReflectionCache.CachedProperty(type, "fontSize"); int currentFontSize3 = (int)fontSizeProperty3.Get(ui); if (object.Equals(_alteredFontSize, currentFontSize3)) { return; } int? size2 = result2.ResizeCommand.GetSize(currentFontSize3); if (size2.HasValue) { fontSizeProperty3.Set(ui, (object)size2.Value); _alteredFontSize = size2.Value; _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { fontSizeProperty3.Set(g, (object)currentFontSize3); }); } return; } TypeContainer textMeshPro = UnityTypes.TextMeshPro; if ((object)unityType != ((textMeshPro != null) ? textMeshPro.UnityType : null)) { TypeContainer textMeshProUGUI = UnityTypes.TextMeshProUGUI; if ((object)unityType != ((textMeshProUGUI != null) ? textMeshProUGUI.UnityType : null)) { return; } } Type type2 = ui.GetType(); CachedProperty overflowModeProperty = ReflectionCache.CachedProperty(type2, "overflowMode"); CachedProperty obj = overflowModeProperty; object originalOverflowMode = ((obj != null) ? obj.Get(ui) : null); bool flag6 = false; bool flag7 = _unresize == null; if (cache.HasAnyResizeCommands) { Component val3 = (Component)ui; if (!Object.op_Implicit((Object)(object)val3) || !Object.op_Implicit((Object)(object)val3.gameObject)) { return; } string[] pathSegments3 = val3.gameObject.GetPathSegments(); int scope3 = TranslationScopeHelper.GetScope(ui); if (cache.TryGetUIResize(pathSegments3, scope3, out var result3)) { if (result3.OverflowCommand != null) { flag6 = true; if (overflowModeProperty != null) { int? mode3 = result3.OverflowCommand.GetMode(); if (mode3.HasValue) { overflowModeProperty.Set(ui, (object)mode3); if (flag7) { _unresize = delegate(object g) { overflowModeProperty.Set(g, originalOverflowMode); }; } } } } if (result3.AlignmentCommand != null) { CachedProperty alignmentProperty = ReflectionCache.CachedProperty(type2, "alignment"); if (alignmentProperty != null) { object alignmentValue = alignmentProperty.Get(ui); int? mode4 = result3.AlignmentCommand.GetMode(); if (mode4.HasValue) { alignmentProperty.Set(ui, (object)mode4.Value); if (flag7) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { alignmentProperty.Set(g, alignmentValue); }); } } } } if (result3.AutoResizeCommand != null) { CachedProperty enableAutoSizingProperty = ReflectionCache.CachedProperty(type2, "enableAutoSizing"); CachedProperty fontSizeMinProperty = ReflectionCache.CachedProperty(type2, "fontSizeMin"); CachedProperty fontSizeMaxProperty = ReflectionCache.CachedProperty(type2, "fontSizeMax"); CachedProperty fontSizeProperty2 = ReflectionCache.CachedProperty(type2, "fontSize"); float? currentFontSize2 = (float?)fontSizeProperty2.Get(ui); if (enableAutoSizingProperty != null) { object enableAutoSizingValue = enableAutoSizingProperty.Get(ui); CachedProperty obj2 = fontSizeMinProperty; object fontSizeMinValue = ((obj2 != null) ? obj2.Get(ui) : null); CachedProperty obj3 = fontSizeMaxProperty; object fontSizeMaxValue = ((obj3 != null) ? obj3.Get(ui) : null); double? minSize = result3.AutoResizeCommand.GetMinSize(); if (minSize.HasValue && fontSizeMinProperty != null) { float num6 = (double.IsNaN(minSize.Value) ? 0f : ((float)minSize.Value)); CachedProperty obj4 = fontSizeMinProperty; if (obj4 != null) { obj4.Set(ui, (object)num6); } } double? maxSize2 = result3.AutoResizeCommand.GetMaxSize(); if (maxSize2.HasValue && fontSizeMaxProperty != null) { float num7 = (double.IsNaN(maxSize2.Value) ? float.MaxValue : ((float)maxSize2.Value)); CachedProperty obj5 = fontSizeMaxProperty; if (obj5 != null) { obj5.Set(ui, (object)num7); } } bool flag8 = result3.AutoResizeCommand.ShouldAutoResize(); enableAutoSizingProperty.Set(ui, (object)flag8); if (flag7) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { enableAutoSizingProperty.Set(g, enableAutoSizingValue); }); if (minSize.HasValue && fontSizeMinProperty != null) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { fontSizeMinProperty.Set(g, fontSizeMinValue); }); } if (maxSize2.HasValue && fontSizeMaxProperty != null) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { fontSizeMaxProperty.Set(g, fontSizeMaxValue); }); } _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { fontSizeProperty2.Set(g, (object)currentFontSize2); }); } } } if (result3.ResizeCommand != null) { CachedProperty fontSizeProperty = ReflectionCache.CachedProperty(type2, "fontSize"); float? currentFontSize = (float?)fontSizeProperty.Get(ui); if (currentFontSize.HasValue) { int num8 = (int)currentFontSize.Value; if (!object.Equals(_alteredFontSize, num8)) { int? size3 = result3.ResizeCommand.GetSize((int)currentFontSize.Value); if (size3.HasValue) { fontSizeProperty.Set(ui, (object)(float)size3.Value); _alteredFontSize = size3.Value; if (flag7) { _unresize = (Action)Delegate.Combine(_unresize, (Action)delegate(object g) { fontSizeProperty.Set(g, (object)currentFontSize); }); } } } } } } } if (flag6 || originalOverflowMode == null || (int)originalOverflowMode != 2) { return; } overflowModeProperty.Set(ui, (object)3); if (flag7) { _unresize = delegate(object g) { overflowModeProperty.Set(g, (object)2); }; } } public void UnresizeUI(object ui) { if (ui != null) { _unresize?.Invoke(ui); _unresize = null; _alteredFontSize = null; } } } internal static class TextTranslationInfoExtensions { public static bool GetIsKnownTextComponent(this TextTranslationInfo info) { return info?.IsKnownTextComponent ?? false; } public static bool GetSupportsStabilization(this TextTranslationInfo info) { return info?.SupportsStabilization ?? false; } } internal class TextureDataResult { public byte[] Data { get; } public bool NonReadable { get; } public float CalculationTime { get; set; } public TextureDataResult(byte[] data, bool nonReadable, float calculationTime) { Data = data; NonReadable = nonReadable; CalculationTime = calculationTime; } } internal enum TextureHashGenerationStrategy { FromImageName, FromImageData, FromImageNameAndScene } internal class TextureReloadContext { private readonly HashSet _textures; public TextureReloadContext() { _textures = new HashSet(); } public bool RegisterTextureInContextAndDetermineWhetherToReload(object texture) { return _textures.Add(texture); } } internal interface ITranslatedImageSource { byte[] GetData(); } internal class ZipFileTranslatedImageSource : ITranslatedImageSource { private readonly ZipFile _zipFile; private readonly ZipEntry _zipEntry; public ZipFileTranslatedImageSource(ZipFile zipFile, ZipEntry zipEntry) { _zipFile = zipFile; _zipEntry = zipEntry; } public byte[] GetData() { using Stream stream = _zipFile.GetInputStream(_zipEntry); return StreamExtensions.ReadFully(stream, 16384); } } internal class FileSystemTranslatedImageSource : ITranslatedImageSource { private readonly string _fileName; public FileSystemTranslatedImageSource(string fileName) { _fileName = fileName; } public byte[] GetData() { using FileStream fileStream = File.OpenRead(_fileName); return StreamExtensions.ReadFully((Stream)fileStream, 16384); } } internal enum ImageFormat { PNG, TGA } internal class TranslatedImage { private static readonly Dictionary Formats = new Dictionary(StringComparer.OrdinalIgnoreCase) { { ".png", ImageFormat.PNG }, { ".tga", ImageFormat.TGA } }; private readonly ITranslatedImageSource _source; private WeakReference _weakData; private byte[] _data; public string FileName { get; } internal ImageFormat ImageFormat { get; } private byte[] Data { get { if (_source == null) { return _data; } byte[] target = _weakData.Target; if (target != null) { return target; } return null; } set { if (_source == null) { _data = value; } else { _weakData = WeakReference.Create(value); } } } public TranslatedImage(string fileName, byte[] data, ITranslatedImageSource source) { _source = source; FileName = fileName; Data = data; ImageFormat = Formats[Path.GetExtension(fileName)]; } public byte[] GetData() { byte[] array = Data; if (array != null) { return array; } if (_source != null) { array = (Data = _source.GetData()); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Image loaded: " + FileName + "."); } } return array; } } internal sealed class TextureTranslationCache : IDisposable { private Dictionary _translatedImages = new Dictionary(StringComparer.InvariantCultureIgnoreCase); private HashSet _untranslatedImages = new HashSet(); private Dictionary _keyToFileName = new Dictionary(); private SafeFileWatcher _fileWatcher; private bool _disposed; public event Action TextureTranslationFileChanged; public TextureTranslationCache() { if (Settings.ReloadTranslationsOnFileChange) { try { Directory.CreateDirectory(Settings.TexturesPath); _fileWatcher = new SafeFileWatcher(Settings.TexturesPath); _fileWatcher.DirectoryUpdated += FileWatcher_DirectoryUpdated; } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while initializing translation file watching for textures."); } } } private void FileWatcher_DirectoryUpdated() { this.TextureTranslationFileChanged?.Invoke(); } private IEnumerable GetTextureFiles() { return from x in Directory.GetFiles(Settings.TexturesPath, "*.*", SearchOption.AllDirectories) where x.EndsWith(".png", StringComparison.OrdinalIgnoreCase) || x.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) select x; } public void LoadTranslationFiles() { try { if (!Settings.EnableTextureTranslation && !Settings.EnableTextureDumping) { return; } float realtimeSinceStartup = Time.realtimeSinceStartup; _translatedImages.Clear(); _untranslatedImages.Clear(); _keyToFileName.Clear(); Directory.CreateDirectory(Settings.TexturesPath); foreach (string textureFile in GetTextureFiles()) { RegisterImageFromFile(textureFile); } float realtimeSinceStartup2 = Time.realtimeSinceStartup; XuaLogger.AutoTranslator.Debug($"Loaded texture files (took {Math.Round(realtimeSinceStartup2 - realtimeSinceStartup, 2)} seconds)"); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading translations."); } } private void RegisterImageFromStream(string fullFileName, ITranslatedImageSource source) { try { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fullFileName); int num = fileNameWithoutExtension.LastIndexOf('['); int num2 = fileNameWithoutExtension.LastIndexOf(']'); if (num2 > -1 && num > -1 && num2 > num) { int num3 = num + 1; string[] array = fileNameWithoutExtension.Substring(num3, num2 - num3).Split(new char[1] { '-' }); string key; string x; if (array.Length == 1) { key = array[0]; x = array[0]; } else { if (array.Length != 2) { XuaLogger.AutoTranslator.Warn("Image not loaded (unknown hash): " + fullFileName + "."); return; } key = array[0]; x = array[1]; } byte[] data = source.GetData(); string y = HashHelper.Compute(data); bool flag = StringComparer.InvariantCultureIgnoreCase.Compare(x, y) != 0; _keyToFileName[key] = fullFileName; if (Settings.LoadUnmodifiedTextures || flag) { RegisterTranslatedImage(fullFileName, key, data, source); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Image loaded: " + fullFileName + "."); } } else { RegisterUntranslatedImage(key); XuaLogger.AutoTranslator.Warn("Image not loaded (unmodified): " + fullFileName + "."); } } else { XuaLogger.AutoTranslator.Warn("Image not loaded (no hash): " + fullFileName + "."); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading texture file: " + fullFileName); } } private void RegisterImageFromFile(string fullFileName) { if (!File.Exists(fullFileName)) { return; } if (fullFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { ZipFile zipFile = new ZipFile(fullFileName); try { foreach (object item in zipFile) { if (item is ZipEntry zipEntry && zipEntry.IsFile && zipEntry.Name.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) { ZipFileTranslatedImageSource source = new ZipFileTranslatedImageSource(zipFile, zipEntry); char directorySeparatorChar = Path.DirectorySeparatorChar; RegisterImageFromStream(fullFileName + directorySeparatorChar + zipEntry.Name, source); } } return; } finally { if (Settings.CacheTexturesInMemory) { zipFile.Close(); } } } FileSystemTranslatedImageSource source2 = new FileSystemTranslatedImageSource(fullFileName); RegisterImageFromStream(fullFileName, source2); } public void RenameFileWithKey(string name, string key, string newKey) { _fileWatcher?.Disable(); try { if (_keyToFileName.TryGetValue(key, out var value)) { _keyToFileName.Remove(key); value.Replace(key, newKey); if (!IsImageRegistered(newKey)) { byte[] data = File.ReadAllBytes(value); RegisterImageFromData(name, newKey, data); File.Delete(value); XuaLogger.AutoTranslator.Warn("Replaced old file with name '" + name + "' registered with key old '" + key + "'."); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while trying to rename file with key '" + key + "'."); } finally { _fileWatcher?.Enable(); } } internal void RegisterImageFromData(string textureName, string key, byte[] data) { _fileWatcher?.Disable(); try { string text = StringExtensions.SanitizeForFileSystem(textureName); string text2 = HashHelper.Compute(data); string text3 = ((!(key == text2)) ? (text + " [" + key + "-" + text2 + "].png") : (text + " [" + key + "].png")); string text4 = Path.Combine(Settings.TexturesPath, text3); File.WriteAllBytes(text4, data); XuaLogger.AutoTranslator.Info("Dumped texture file: " + text3); _keyToFileName[key] = text4; if (Settings.LoadUnmodifiedTextures) { FileSystemTranslatedImageSource source = new FileSystemTranslatedImageSource(text4); RegisterTranslatedImage(text4, key, data, source); } else { RegisterUntranslatedImage(key); } } finally { _fileWatcher?.Enable(); } } private void RegisterTranslatedImage(string fileName, string key, byte[] data, ITranslatedImageSource source) { _translatedImages[key] = new TranslatedImage(fileName, data, Settings.CacheTexturesInMemory ? null : source); } private void RegisterUntranslatedImage(string key) { _untranslatedImages.Add(key); } internal bool IsImageRegistered(string key) { if (!_translatedImages.ContainsKey(key)) { return _untranslatedImages.Contains(key); } return true; } internal bool TryGetTranslatedImage(string key, out byte[] data, out TranslatedImage image) { if (_translatedImages.TryGetValue(key, out var value)) { try { data = value.GetData(); image = value; return data != null; } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurrd while attempting to load image: " + value.FileName); _translatedImages.Remove(key); } } data = null; image = null; return false; } private void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _fileWatcher?.Dispose(); } _disposed = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } internal class TextureTranslationInfo { private static Dictionary NameToHash = new Dictionary(); private static readonly Encoding UTF8 = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); private string _key; private byte[] _originalData; private bool _initialized; private TextureFormat _textureFormat; public WeakReference Original { get; private set; } public Texture2D Translated { get; private set; } public Sprite TranslatedSprite { get; set; } public bool IsTranslated { get; set; } public bool IsDumped { get; set; } public bool UsingReplacedTexture { get; set; } public void Initialize(Texture2D texture) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!_initialized) { _initialized = true; _textureFormat = texture.format; SetOriginal(texture); } } public void SetOriginal(Texture2D texture) { Original = WeakReference.Create(texture); } private void SetTranslated(Texture2D texture) { Translated = texture; } public void CreateTranslatedTexture(byte[] newData, ImageFormat format) { //IL_001b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)Translated == (Object)null) { Texture2D target = Original.Target; Texture2D val = ComponentHelper.CreateEmptyTexture2D(_textureFormat); val.LoadImageEx(newData, format, target); SetTranslated(val); ExtensionDataHelper.SetExtensionData((object)val, this); UsingReplacedTexture = true; } } public void CreateOriginalTexture() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) if (!((WeakReference)(object)Original).IsAlive && _originalData != null) { Texture2D val = ComponentHelper.CreateEmptyTexture2D(_textureFormat); val.LoadImageEx(_originalData, ImageFormat.PNG, null); SetOriginal(val); } } public string GetKey() { SetupHashAndData(Original.Target); return _key; } public byte[] GetOriginalData() { SetupHashAndData(Original.Target); return _originalData; } public byte[] GetOrCreateOriginalData() { SetupHashAndData(Original.Target); if (_originalData != null) { return _originalData; } return Original.Target.GetTextureData().Data; } private TextureDataResult SetupKeyForNameWithFallback(string name, Texture2D texture) { bool flag = false; string value = null; string text = null; TextureDataResult textureDataResult = null; if (Settings.DetectDuplicateTextureNames) { textureDataResult = texture.GetTextureData(); text = HashHelper.Compute(textureDataResult.Data); if (NameToHash.TryGetValue(name, out value)) { if (value != text) { XuaLogger.AutoTranslator.Warn("Detected duplicate image name: " + name); flag = true; Settings.AddDuplicateName(name); } } else { NameToHash[name] = text; } } if (Settings.DuplicateTextureNames.Contains(name)) { if (text == null) { if (textureDataResult == null) { textureDataResult = texture.GetTextureData(); } text = HashHelper.Compute(textureDataResult.Data); } _key = text; } else { _key = HashHelper.Compute(UTF8.GetBytes(name)); } if (flag && Settings.EnableTextureDumping) { string key = HashHelper.Compute(UTF8.GetBytes(name)); AutoTranslationPlugin.Current.TextureCache.RenameFileWithKey(name, key, value); } return textureDataResult; } private void SetupHashAndData(Texture2D texture) { if (_key != null) { return; } if (Settings.TextureHashGenerationStrategy == TextureHashGenerationStrategy.FromImageData) { TextureDataResult textureData = texture.GetTextureData(); _originalData = textureData.Data; _key = HashHelper.Compute(_originalData); } else if (Settings.TextureHashGenerationStrategy == TextureHashGenerationStrategy.FromImageName) { string textureName = texture.GetTextureName(null); if (textureName == null) { return; } TextureDataResult textureDataResult = SetupKeyForNameWithFallback(textureName, texture); if (Settings.EnableTextureToggling || Settings.DetectDuplicateTextureNames) { if (textureDataResult == null) { textureDataResult = texture.GetTextureData(); } _originalData = textureDataResult.Data; } } else { if (Settings.TextureHashGenerationStrategy != TextureHashGenerationStrategy.FromImageNameAndScene) { return; } string textureName2 = texture.GetTextureName(null); if (textureName2 == null) { return; } textureName2 = textureName2 + "|" + TranslationScopeHelper.GetActiveSceneId(); TextureDataResult textureDataResult2 = SetupKeyForNameWithFallback(textureName2, texture); if (Settings.EnableTextureToggling || Settings.DetectDuplicateTextureNames) { if (textureDataResult2 == null) { textureDataResult2 = texture.GetTextureData(); } _originalData = textureDataResult2.Data; } } } } public class UnityEngineTime : ITime { public float realtimeSinceStartup => Time.realtimeSinceStartup; public int frameCount => Time.frameCount; } public class TimeSupport { public static ITime Time { get; set; } = new UnityEngineTime(); } public interface ITime { float realtimeSinceStartup { get; } int frameCount { get; } } internal class TransformInfo { public IReadOnlyTextTranslationCache TextCache { get; set; } } internal class TranslationFileLoadingContext { public class SetLevelTranslationFileDirective : TranslationFileDirective { public int[] Levels { get; } public SetLevelTranslationFileDirective(int[] levels) { Levels = levels; } public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { int[] levels = Levels; foreach (int item in levels) { context._levels.Add(item); } } } public override string ToString() { return "#set level " + string.Join(",", Levels.Select((int x) => x.ToString(CultureInfo.InvariantCulture)).ToArray()); } } public struct ResolutionCheckVariables { public int Width { get; } public int Height { get; } public ResolutionCheckVariables(int width, int height) { Width = width; Height = height; } } public class SetRequiredResolutionTranslationFileDirective : TranslationFileDirective { private readonly string _expression; private readonly Func _predicate; public SetRequiredResolutionTranslationFileDirective(string expression) { _expression = expression; _predicate = DynamicLinq.DynamicExpression.ParseLambda(expression, new object[0]).Compile(); } public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { context._resolutionCheck = _predicate; } } public override string ToString() { return "#set required-resolution " + _expression; } } public class UnsetRequiredResolutionTranslationFileDirective : TranslationFileDirective { public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { context._resolutionCheck = DefaultResolutionCheck; } } public override string ToString() { return "#unset required-resolution"; } } public class UnsetLevelTranslationFileDirective : TranslationFileDirective { public int[] Levels { get; } public UnsetLevelTranslationFileDirective(int[] levels) { Levels = levels; } public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { int[] levels = Levels; foreach (int item in levels) { context._levels.Remove(item); } } } public override string ToString() { return "#unset level " + string.Join(",", Levels.Select((int x) => x.ToString(CultureInfo.InvariantCulture)).ToArray()); } } public class SetExeTranslationFileDirective : TranslationFileDirective { public string[] Executables { get; } public SetExeTranslationFileDirective(string[] executables) { Executables = executables; } public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { string[] executables = Executables; foreach (string item in executables) { context._executables.Add(item); } } } public override string ToString() { return "#set exe " + string.Join(",", Executables); } } public class UnsetExeTranslationFileDirective : TranslationFileDirective { public string[] Executables { get; } public UnsetExeTranslationFileDirective(string[] executables) { Executables = executables; } public override void ModifyContext(TranslationFileLoadingContext context) { if (Settings.EnableTranslationScoping) { string[] executables = Executables; foreach (string item in executables) { context._executables.Remove(item); } } } public override string ToString() { return "#unset exe " + string.Join(",", Executables); } } public class EnableTranslationFileDirective : TranslationFileDirective { public string Tag { get; } public EnableTranslationFileDirective(string tag) { Tag = tag; } public override void ModifyContext(TranslationFileLoadingContext context) { if (Tag != null) { context._enabledTags.Add(Tag); } } public override string ToString() { return "#enable " + Tag; } } private static readonly Func DefaultResolutionCheck = (ResolutionCheckVariables x) => true; private HashSet _executables = new HashSet(StringComparer.OrdinalIgnoreCase); private HashSet _levels = new HashSet(); private HashSet _enabledTags = new HashSet(StringComparer.OrdinalIgnoreCase); private Func _resolutionCheck = DefaultResolutionCheck; public bool IsApplicable() { if (IsValidExecutable()) { return _resolutionCheck(new ResolutionCheckVariables(Screen.width, Screen.height)); } return false; } public bool IsValidExecutable() { if (_executables.Count == 0) { return true; } return _executables.Contains(Settings.ApplicationName); } public HashSet GetLevels() { return _levels; } public bool IsEnabled(string tag) { return _enabledTags.Contains(tag); } public void Apply(TranslationFileDirective directive) { directive.ModifyContext(this); } } internal abstract class TranslationFileDirective { public static TranslationFileDirective Create(string directive) { int num = directive.IndexOf("//", StringComparison.Ordinal); if (num > -1) { directive = directive.Substring(0, num); } directive = directive.Trim(); if (directive.Length > 0 && directive[0] == '#') { string[] array = directive.Split(new char[1] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (array.Length >= 2) { string text = array[0].ToLowerInvariant(); string text2 = array[1]; string argument = directive.Substring(directive.IndexOf(text2, StringComparison.Ordinal) + text2.Length).Trim(); text2 = text2.ToLowerInvariant(); switch (text) { case "#set": return CreateSetCommand(text2, argument); case "#unset": return CreateUnsetCommand(text2, argument); case "#enable": return CreateEnableCommand(text2, argument); } } } return null; } private static TranslationFileDirective CreateSetCommand(string setType, string argument) { return setType switch { "required-resolution" => new TranslationFileLoadingContext.SetRequiredResolutionTranslationFileDirective(argument), "level" => new TranslationFileLoadingContext.SetLevelTranslationFileDirective(ParseCommaSeperatedListAsIntArray(argument)), "exe" => new TranslationFileLoadingContext.SetExeTranslationFileDirective(ParseCommaSeperatedListAsStringArray(argument)), _ => null, }; } private static TranslationFileDirective CreateUnsetCommand(string setType, string argument) { return setType switch { "required-resolution" => new TranslationFileLoadingContext.UnsetRequiredResolutionTranslationFileDirective(), "level" => new TranslationFileLoadingContext.UnsetLevelTranslationFileDirective(ParseCommaSeperatedListAsIntArray(argument)), "exe" => new TranslationFileLoadingContext.UnsetExeTranslationFileDirective(ParseCommaSeperatedListAsStringArray(argument)), _ => null, }; } private static TranslationFileDirective CreateEnableCommand(string setType, string argument) { return new TranslationFileLoadingContext.EnableTranslationFileDirective(setType); } private static int[] ParseCommaSeperatedListAsIntArray(string argument) { if (string.IsNullOrEmpty(argument)) { return new int[0]; } List list = new List(); string[] array = argument.Split(new char[2] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (int.TryParse(array[i], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { list.Add(result); } } return list.ToArray(); } private static string[] ParseCommaSeperatedListAsStringArray(string argument) { if (string.IsNullOrEmpty(argument)) { return new string[0]; } return (from x in argument.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries) select x.Trim()).ToArray(); } public abstract void ModifyContext(TranslationFileLoadingContext context); } public static class TranslationHelper { private static Dictionary> _registrations = new Dictionary>(); private static List LookupRegistration(IEnumerable keys) { HashSet hashSet = new HashSet(); foreach (UntranslatedText key in keys) { if (_registrations.TryGetValue(key.TemplatedOriginal_Text, out var value)) { hashSet.AddRange(value); } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed && _registrations.TryGetValue(key.TemplatedOriginal_Text_ExternallyTrimmed, out value)) { hashSet.AddRange(value); } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed && _registrations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value)) { hashSet.AddRange(value); } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed && _registrations.TryGetValue(key.TemplatedOriginal_Text_FullyTrimmed, out value)) { hashSet.AddRange(value); } } List list = hashSet.ToList(); list.Sort(); return list; } internal static void DisplayTranslationInfo(string originalText, string translatedText) { if (!Settings.EnableTranslationHelper) { return; } UntranslatedText item = CreateTextKey(originalText); List list = new List { item }; if (translatedText != null) { UntranslatedText item2 = CreateTextKey(translatedText); list.Add(item2); } List list2 = LookupRegistration(list); if (list2.Count <= 0) { return; } StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(); if (translatedText != null) { stringBuilder.Append("For the text \"").Append(originalText).AppendLine("\", which was translated to \"" + translatedText + "\" found the following potential source files:"); } else { stringBuilder.Append("For the text \"").Append(originalText).AppendLine("\" found the following potential source files:"); } foreach (string item3 in list2) { stringBuilder.Append(" ").AppendLine(item3); } XuaLogger.AutoTranslator.Info(stringBuilder.ToString()); } public static void RegisterRedirectedResourceTextToPath(string text, string virtualFilePath) { if (Settings.EnableTranslationHelper) { AssociateTextKeyWithFile(CreateTextKey(text), virtualFilePath); } } private static UntranslatedText CreateTextKey(string text) { if (LanguageHelper.IsTranslatable(text)) { return new UntranslatedText(text, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); } return new UntranslatedText(text, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.ToLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); } private static void AssociateTextKeyWithFile(UntranslatedText key, string virtualFilePath) { AssociateTextWithFile(key.TemplatedOriginal_Text, virtualFilePath); if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { AssociateTextWithFile(key.TemplatedOriginal_Text_ExternallyTrimmed, virtualFilePath); } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { AssociateTextWithFile(key.TemplatedOriginal_Text_InternallyTrimmed, virtualFilePath); } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { AssociateTextWithFile(key.TemplatedOriginal_Text_FullyTrimmed, virtualFilePath); } } private static void AssociateTextWithFile(string text, string virtualFilePath) { if (!_registrations.TryGetValue(text, out var value)) { value = new HashSet(); _registrations[text] = value; } value.Add(virtualFilePath); } } internal class TranslationJob { public bool IsTranslatable { get; } public bool SaveResultGlobally { get; private set; } public bool AllowFallback { get; private set; } public TranslationEndpointManager Endpoint { get; internal set; } public HashSet Contexts { get; private set; } public List> Components { get; private set; } public HashSet> TranslationResults { get; private set; } public UntranslatedText Key { get; private set; } public UntranslatedTextInfo UntranslatedTextInfo { get; set; } public string TranslatedText { get; set; } public string ErrorMessage { get; set; } public TranslationJobState State { get; set; } public TranslationType TranslationType { get; set; } public bool ShouldPersistTranslation { get { bool flag = (TranslationType & TranslationType.Full) == TranslationType.Full; if (!flag) { return Contexts.Any((ParserTranslationContext x) => x.Result.PersistTokenResult); } return flag; } } public TranslationJob(TranslationEndpointManager endpoint, UntranslatedText key, bool saveResult, bool isTranslatable) { Endpoint = endpoint; Key = key; SaveResultGlobally = saveResult; IsTranslatable = isTranslatable; Components = new List>(); Contexts = new HashSet(); TranslationResults = new HashSet>(); } public void Associate(UntranslatedText key, object ui, InternalTranslationResult translationResult, ParserTranslationContext context, UntranslatedTextInfo untranslatedTextInfo, bool saveResultGlobally, bool allowFallback) { AllowFallback = allowFallback || AllowFallback; if (UntranslatedTextInfo == null && untranslatedTextInfo != null) { UntranslatedTextInfo = untranslatedTextInfo; } SaveResultGlobally |= saveResultGlobally; if (context != null) { Contexts.Add(context); context.Jobs.Add(this); TranslationType |= TranslationType.Token; return; } if (ui != null && !ui.IsSpammingComponent()) { Components.Add(new KeyAnd(key, ui)); } if (translationResult != null) { TranslationResults.Add(new KeyAnd(key, translationResult)); } TranslationType |= TranslationType.Full; } } internal class KeyAnd { public UntranslatedText Key { get; set; } public T Item { get; set; } public KeyAnd(UntranslatedText key, T item) { Key = key; Item = item; } } internal enum TranslationJobState { RunningOrQueued, Succeeded, Failed } internal class TranslationManager { private readonly List _updateCallbacks; private readonly List _endpointsWithUnstartedJobs; public int OngoingTranslations { get; set; } public int UnstartedTranslations { get; set; } public List ConfiguredEndpoints { get; private set; } public List AllEndpoints { get; private set; } public TranslationEndpointManager CurrentEndpoint { get; set; } public TranslationEndpointManager FallbackEndpoint { get; set; } public TranslationEndpointManager PassthroughEndpoint { get; private set; } public event Action JobCompleted; public event Action JobFailed; public TranslationManager() { _updateCallbacks = new List(); _endpointsWithUnstartedJobs = new List(); ConfiguredEndpoints = new List(); AllEndpoints = new List(); } public bool IsFallbackAvailableFor(TranslationEndpointManager endpoint) { if (endpoint != null && FallbackEndpoint != null && endpoint == CurrentEndpoint) { return FallbackEndpoint != endpoint; } return false; } public void InitializeEndpoints() { try { HttpSecurity httpSecurity = new HttpSecurity(); CreateEndpoints(httpSecurity); AllEndpoints = (from x in AllEndpoints orderby x.Error != null, x.Endpoint.FriendlyName select x).ToList(); PassthroughEndpoint = AllEndpoints.FirstOrDefault((TranslationEndpointManager x) => x.Endpoint is PassthroughTranslateEndpoint); TranslationEndpointManager translationEndpointManager = AllEndpoints.FirstOrDefault((TranslationEndpointManager x) => x.Endpoint.Id == Settings.FallbackServiceEndpoint); if (translationEndpointManager != null) { if (translationEndpointManager.Error != null) { XuaLogger.AutoTranslator.Error(translationEndpointManager.Error, "Error occurred during the initialization of the fallback translate endpoint."); } else { FallbackEndpoint = translationEndpointManager; } } TranslationEndpointManager translationEndpointManager2 = AllEndpoints.FirstOrDefault((TranslationEndpointManager x) => x.Endpoint.Id == Settings.ServiceEndpoint); if (translationEndpointManager2 != null) { if (translationEndpointManager2.Error != null) { XuaLogger.AutoTranslator.Error(translationEndpointManager2.Error, "Error occurred during the initialization of the selected translate endpoint."); } else { if (translationEndpointManager == translationEndpointManager2) { XuaLogger.AutoTranslator.Warn("Cannot use same fallback endpoint as primary."); } CurrentEndpoint = translationEndpointManager2; } } else if (!string.IsNullOrEmpty(Settings.ServiceEndpoint)) { XuaLogger.AutoTranslator.Error("Could not find the configured endpoint '" + Settings.ServiceEndpoint + "'."); } if (Settings.DisableCertificateValidation) { XuaLogger.AutoTranslator.Debug("Disabling certificate checks for endpoints because of configuration."); ServicePointManager.ServerCertificateValidationCallback = (RemoteCertificateValidationCallback)Delegate.Combine(ServicePointManager.ServerCertificateValidationCallback, (RemoteCertificateValidationCallback)((object a1, X509Certificate a2, X509Chain a3, SslPolicyErrors a4) => true)); } else { RemoteCertificateValidationCallback certificateValidationCheck = httpSecurity.GetCertificateValidationCheck(); if (certificateValidationCheck != null && !ClrFeatures.SupportsNet4x) { XuaLogger.AutoTranslator.Debug("Disabling certificate checks for endpoints because a .NET 3.x runtime is used."); ServicePointManager.ServerCertificateValidationCallback = (RemoteCertificateValidationCallback)Delegate.Combine(ServicePointManager.ServerCertificateValidationCallback, certificateValidationCheck); } else { XuaLogger.AutoTranslator.Debug("Not disabling certificate checks for endpoints because a .NET 4.x runtime is used."); } } Settings.Save(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while constructing endpoints. Shutting plugin down."); Settings.IsShutdown = true; } } public void CreateEndpoints(HttpSecurity httpSecurity) { if (Settings.FromLanguage != Settings.Language) { List allTypesOf = AssemblyLoader.GetAllTypesOf(Settings.TranslatorsPath); allTypesOf.Add(typeof(PassthroughTranslateEndpoint)); { foreach (Type item in allTypesOf) { AddEndpoint(httpSecurity, item); } return; } } XuaLogger.AutoTranslator.Warn("AutoTranslator has been configured to use same destination language as source language. All translators will be disabled!"); } private void AddEndpoint(HttpSecurity httpSecurity, Type type) { ITranslateEndpoint translateEndpoint; try { translateEndpoint = (ITranslateEndpoint)Activator.CreateInstance(type); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "Could not instantiate class: " + type.Name); return; } InitializationContext context = new InitializationContext(httpSecurity, Settings.FromLanguage, Settings.Language); try { translateEndpoint.Initialize(context); TranslationEndpointManager translationEndpointManager = new TranslationEndpointManager(translateEndpoint, null, context); RegisterEndpoint(translationEndpointManager); } catch (Exception error) { TranslationEndpointManager translationEndpointManager2 = new TranslationEndpointManager(translateEndpoint, error, context); RegisterEndpoint(translationEndpointManager2); } } public void Update() { int count = _updateCallbacks.Count; for (int i = 0; i < count; i++) { try { _updateCallbacks[i].Update(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while calling update on " + _updateCallbacks[i].GetType().Name + "."); } } } public void KickoffTranslations() { List endpointsWithUnstartedJobs = _endpointsWithUnstartedJobs; for (int num = endpointsWithUnstartedJobs.Count - 1; num >= 0; num--) { TranslationEndpointManager translationEndpointManager = endpointsWithUnstartedJobs[num]; if (Settings.EnableBatching && translationEndpointManager.CanBatch) { while (translationEndpointManager.HasUnstartedBatch && !translationEndpointManager.IsBusy) { translationEndpointManager.HandleNextBatch(); } } else { while (translationEndpointManager.HasUnstartedJob && !translationEndpointManager.IsBusy) { translationEndpointManager.HandleNextJob(); } } } } public void ScheduleUnstartedJobs(TranslationEndpointManager endpoint) { _endpointsWithUnstartedJobs.Add(endpoint); } public void UnscheduleUnstartedJobs(TranslationEndpointManager endpoint) { _endpointsWithUnstartedJobs.Remove(endpoint); } public void ClearAllJobs() { foreach (TranslationEndpointManager configuredEndpoint in ConfiguredEndpoints) { configuredEndpoint.ClearAllJobs(); } } public void RebootAllEndpoints() { foreach (TranslationEndpointManager configuredEndpoint in ConfiguredEndpoints) { configuredEndpoint.ConsecutiveErrors = 0; } } public void RegisterEndpoint(TranslationEndpointManager translationEndpointManager) { translationEndpointManager.Manager = this; AllEndpoints.Add(translationEndpointManager); if (translationEndpointManager.Error == null) { ConfiguredEndpoints.Add(translationEndpointManager); } if (translationEndpointManager.Endpoint is IMonoBehaviour_Update item) { _updateCallbacks.Add(item); } } public void InvokeJobCompleted(TranslationJob job) { this.JobCompleted?.Invoke(job); } public void InvokeJobFailed(TranslationJob job) { this.JobFailed?.Invoke(job); } } public static class TranslationRegistry { public static ITranslationRegistry Default => AutoTranslationPlugin.Current; } public interface ITranslationRegistry { void RegisterPluginSpecificTranslations(Assembly assembly, StreamTranslationPackage package); void RegisterPluginSpecificTranslations(Assembly assembly, KeyValuePairTranslationPackage package); void EnablePluginTranslationFallback(Assembly assembly); } public static class TranslationRegistryExtensions { private static Assembly GetCallingPlugin() { MethodBase method = new StackFrame(2).GetMethod(); if ((object)method != null) { return method.DeclaringType.Assembly; } throw new ArgumentException("Could not automatically determine the calling plugin. Consider calling the overload of this method taking an assembly name."); } public static void RegisterPluginSpecificTranslations(this ITranslationRegistry registry, StreamTranslationPackage package) { Assembly callingPlugin = GetCallingPlugin(); registry.RegisterPluginSpecificTranslations(callingPlugin, package); } public static void RegisterPluginSpecificTranslations(this ITranslationRegistry registry, KeyValuePairTranslationPackage package) { Assembly callingPlugin = GetCallingPlugin(); registry.RegisterPluginSpecificTranslations(callingPlugin, package); } public static void EnablePluginTranslationFallback(this ITranslationRegistry registry) { Assembly callingPlugin = GetCallingPlugin(); registry.EnablePluginTranslationFallback(callingPlugin); } } public class TranslationResult { public bool Succeeded => ErrorMessage == null; public string TranslatedText { get; } public string ErrorMessage { get; } internal TranslationResult(string translatedText, string errorMessage) { TranslatedText = translatedText; ErrorMessage = errorMessage; } } [Flags] internal enum TranslationType { None = 0, Full = 1, Token = 2 } internal class UntranslatedText { private bool? _isOnlyTemplate; public bool IsFromSpammingComponent { get; set; } public string LeadingWhitespace { get; } public string TrailingWhitespace { get; } public string Original_Text { get; } public string Original_Text_ExternallyTrimmed { get; } public string Original_Text_InternallyTrimmed { get; } public string Original_Text_FullyTrimmed { get; } public string TemplatedOriginal_Text { get; } public string TemplatedOriginal_Text_ExternallyTrimmed { get; } public string TemplatedOriginal_Text_InternallyTrimmed { get; } public string TemplatedOriginal_Text_FullyTrimmed { get; } public TemplatedString TemplatedText { get; } public bool IsTemplated => TemplatedText != null; public bool IsOnlyTemplate { get { if (!_isOnlyTemplate.HasValue) { _isOnlyTemplate = IsTemplated && !TemplatingHelper.ContainsUntemplatedCharacters(TemplatedOriginal_Text_ExternallyTrimmed); } return _isOnlyTemplate.Value; } } private static string PerformInternalTrimming(string text, bool whitespaceBetweenWords, ref StringBuilder builder) { if (builder != null) { builder.Length = 0; } else if (builder == null) { builder = new StringBuilder(64); } bool flag = false; int length = text.Length; int num = -1; int i; for (i = 0; i < length; i++) { char c = text[i]; if (c == '\n') { int num2 = i - 1; while (num2 >= 0 && char.IsWhiteSpace(text[num2])) { num2--; } int j; for (j = i + 1; j < length && char.IsWhiteSpace(text[j]); j++) { } num2++; j--; int num3 = j - num2; char c2 = '\0'; if (num3 > 0) { int num4 = 0; char c3 = text[num2]; bool flag2 = false; num2++; for (int k = num2; k <= j; k++) { char c4 = text[k]; if (c4 == c3) { if (!flag2) { num4++; builder.Append(c3); flag2 = true; } num4++; builder.Append(c4); c2 = c4; } else if (c3 == '\r' && c4 == '\n') { int index = k + 1; int index2 = k + 2; if (k + 2 > j) { continue; } char num5 = text[index]; char c5 = text[index2]; if (num5 == '\r' && c5 == '\n') { if (!flag2) { num4++; builder.Append('\r'); builder.Append('\n'); flag2 = true; } num4++; builder.Append('\r'); builder.Append('\n'); c2 = '\n'; k++; } } else { flag2 = false; c3 = c4; } } if (num4 - 1 != num3) { flag = true; } } else { flag = true; } if (whitespaceBetweenWords && !char.IsWhiteSpace(c2) && builder.Length > 0 && builder[builder.Length - 1] != ' ') { flag = true; builder.Append(' '); } i = j; num = -1; } else if (!char.IsWhiteSpace(c)) { if (num != -1) { for (int l = num; l < i; l++) { builder.Append(text[l]); } num = -1; } builder.Append(c); } else if (num == -1) { num = i; } } if (num != -1) { for (int m = num; m < i; m++) { builder.Append(text[m]); } } if (flag) { return builder.ToString(); } return text; } private static string SurroundWithWhitespace(string text, string leadingWhitespace, string trailingWhitespace, ref StringBuilder builder) { if (leadingWhitespace != null || trailingWhitespace != null) { if (builder != null) { builder.Length = 0; } else if (builder == null) { builder = new StringBuilder(64); } if (leadingWhitespace != null) { builder.Append(leadingWhitespace); } builder.Append(text); if (trailingWhitespace != null) { builder.Append(trailingWhitespace); } return builder.ToString(); } return text; } public UntranslatedText(string originalText, bool isFromSpammingComponent, bool removeInternalWhitespace, bool whitespaceBetweenWords, bool enableTemplating, bool templateAllNumbersAway) { IsFromSpammingComponent = isFromSpammingComponent; Original_Text = originalText; if (enableTemplating) { if (isFromSpammingComponent) { TemplatedText = originalText.TemplatizeByNumbers(); if (TemplatedText != null) { originalText = TemplatedText.Template; } } else { TemplatedText = (templateAllNumbersAway ? originalText.TemplatizeByReplacementsAndNumbers() : originalText.TemplatizeByReplacements()); if (TemplatedText != null) { originalText = TemplatedText.Template; } } } TemplatedOriginal_Text = originalText; bool isTemplated = IsTemplated; int i = 0; StringBuilder stringBuilder = null; for (; i < originalText.Length && char.IsWhiteSpace(originalText[i]); i++) { if (stringBuilder == null) { stringBuilder = new StringBuilder(64); } stringBuilder.Append(originalText[i]); } if (i != 0) { LeadingWhitespace = stringBuilder?.ToString(); } StringBuilder builder = stringBuilder; if (i != originalText.Length) { i = originalText.Length - 1; if (builder != null) { builder.Length = 0; } while (i > -1 && char.IsWhiteSpace(originalText[i])) { if (builder == null) { builder = new StringBuilder(64); } builder.Append(originalText[i]); i--; } if (i != originalText.Length - 1) { TrailingWhitespace = builder?.Reverse().ToString(); } } int num = ((LeadingWhitespace != null) ? LeadingWhitespace.Length : 0); int num2 = ((TrailingWhitespace != null) ? TrailingWhitespace.Length : 0); if (num > 0 || num2 > 0) { Original_Text_ExternallyTrimmed = Original_Text.Substring(num, Original_Text.Length - num2 - num); } else { Original_Text_ExternallyTrimmed = Original_Text; } if (isTemplated) { TemplatedOriginal_Text_ExternallyTrimmed = TemplatedOriginal_Text.Substring(num, TemplatedOriginal_Text.Length - num2 - num); } else { TemplatedOriginal_Text_ExternallyTrimmed = Original_Text_ExternallyTrimmed; } if (removeInternalWhitespace) { Original_Text_FullyTrimmed = PerformInternalTrimming(Original_Text_ExternallyTrimmed, whitespaceBetweenWords, ref builder); bool flag = (object)Original_Text_FullyTrimmed == Original_Text_ExternallyTrimmed; Original_Text_InternallyTrimmed = (flag ? Original_Text : SurroundWithWhitespace(Original_Text_FullyTrimmed, LeadingWhitespace, TrailingWhitespace, ref builder)); } else { Original_Text_FullyTrimmed = Original_Text_ExternallyTrimmed; Original_Text_InternallyTrimmed = Original_Text; } if (isTemplated) { if (removeInternalWhitespace) { TemplatedOriginal_Text_FullyTrimmed = PerformInternalTrimming(TemplatedOriginal_Text_ExternallyTrimmed, whitespaceBetweenWords, ref builder); bool flag2 = (object)TemplatedOriginal_Text_FullyTrimmed == TemplatedOriginal_Text_ExternallyTrimmed; TemplatedOriginal_Text_InternallyTrimmed = (flag2 ? TemplatedOriginal_Text : SurroundWithWhitespace(TemplatedOriginal_Text_FullyTrimmed, LeadingWhitespace, TrailingWhitespace, ref builder)); } else { TemplatedOriginal_Text_FullyTrimmed = TemplatedOriginal_Text_ExternallyTrimmed; TemplatedOriginal_Text_InternallyTrimmed = TemplatedOriginal_Text; } } else { TemplatedOriginal_Text_FullyTrimmed = Original_Text_FullyTrimmed; TemplatedOriginal_Text_InternallyTrimmed = Original_Text_InternallyTrimmed; } } public string Untemplate(string text) { if (TemplatedText != null) { return TemplatedText.Untemplate(text); } return text; } public string PrepareUntranslatedText(string text) { if (TemplatedText != null) { return TemplatedText.PrepareUntranslatedText(text); } return text; } public string FixTranslatedText(string text, bool useTranslatorFriendlyArgs) { if (TemplatedText != null) { return TemplatedText.FixTranslatedText(text, useTranslatorFriendlyArgs); } return text; } public override bool Equals(object obj) { if (obj is UntranslatedText untranslatedText) { return TemplatedOriginal_Text_InternallyTrimmed == untranslatedText.TemplatedOriginal_Text_InternallyTrimmed; } return false; } public override int GetHashCode() { return TemplatedOriginal_Text_InternallyTrimmed.GetHashCode(); } } internal enum WhitespaceHandlingStrategy { TrimPerNewline, None } internal static class GeneratedInfo { public const string PROJECT_VERSION = "5.6.1"; } } namespace XUnity.AutoTranslator.Plugin.Core.Web { internal class HttpSecurity { public readonly HashSet _hosts = new HashSet(); public void EnableSslFor(params string[] hosts) { foreach (string item in hosts) { _hosts.Add(item); } } internal RemoteCertificateValidationCallback GetCertificateValidationCheck() { if (_hosts.Count == 0) { return null; } return (object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors) => sender is HttpWebRequest httpWebRequest && _hosts.Contains(httpWebRequest.Address.Host); } } public class XUnityWebClient : ConnectionTrackingWebClient { private HttpStatusCode? _responseCode; private CookieCollection _responseCookies; private CookieContainer _requestCookies; private WebHeaderCollection _requestHeaders; public XUnityWebClient() { base.Encoding = Encoding.UTF8; } private void UnityWebClient_UploadStringCompleted(object sender, XUnityUploadStringCompletedEventArgs ev) { base.UploadStringCompleted -= UnityWebClient_UploadStringCompleted; XUnityWebResponse xUnityWebResponse = ev.UserState as XUnityWebResponse; try { xUnityWebResponse.SetCompleted(_responseCode.HasValue ? _responseCode.Value : HttpStatusCode.BadRequest, ev.Result, responseHeaders, _responseCookies, ev.Error); } catch (Exception) { xUnityWebResponse.SetCompleted(_responseCode.HasValue ? _responseCode.Value : HttpStatusCode.BadRequest, null, responseHeaders, _responseCookies, ev.Error); } } private void UnityWebClient_DownloadStringCompleted(object sender, XUnityDownloadStringCompletedEventArgs ev) { base.DownloadStringCompleted -= UnityWebClient_DownloadStringCompleted; XUnityWebResponse xUnityWebResponse = ev.UserState as XUnityWebResponse; try { xUnityWebResponse.SetCompleted(_responseCode.HasValue ? _responseCode.Value : HttpStatusCode.BadRequest, ev.Result, responseHeaders, _responseCookies, ev.Error); } catch (Exception) { xUnityWebResponse.SetCompleted(_responseCode.HasValue ? _responseCode.Value : HttpStatusCode.BadRequest, null, responseHeaders, _responseCookies, ev.Error); } } protected override WebRequest GetWebRequest(Uri address) { WebRequest webRequest = base.GetWebRequest(address); SetRequestVariables(webRequest); return webRequest; } protected override WebResponse GetWebResponse(WebRequest request, IAsyncResult result) { WebResponse webResponse = base.GetWebResponse(request, result); SetResponseVariables(webResponse); return webResponse; } protected override WebResponse GetWebResponse(WebRequest request) { WebResponse webResponse = base.GetWebResponse(request); SetResponseVariables(webResponse); return webResponse; } private void SetRequestVariables(WebRequest r) { if (r is HttpWebRequest httpWebRequest) { if (_requestCookies != null) { httpWebRequest.CookieContainer = _requestCookies; } if (_requestHeaders != null) { base.Headers = _requestHeaders; } httpWebRequest.ReadWriteTimeout = (int)(Settings.Timeout * 1000f) - 10000; httpWebRequest.Timeout = (int)(Settings.Timeout * 1000f) - 5000; } } private void SetResponseVariables(WebResponse r) { if (r is HttpWebResponse httpWebResponse) { _responseCode = httpWebResponse.StatusCode; _responseCookies = httpWebResponse.Cookies; } } public XUnityWebResponse Send(XUnityWebRequest request) { XUnityWebResponse xUnityWebResponse = new XUnityWebResponse(); _requestCookies = request.Cookies; _requestHeaders = request.Headers; if (request.Data == null) { try { base.DownloadStringCompleted += UnityWebClient_DownloadStringCompleted; DownloadStringAsync(request.Address, xUnityWebResponse); } catch { base.DownloadStringCompleted -= UnityWebClient_DownloadStringCompleted; throw; } } else { try { base.UploadStringCompleted += UnityWebClient_UploadStringCompleted; UploadStringAsync(request.Address, request.Method, request.Data, xUnityWebResponse); } catch { base.UploadStringCompleted -= UnityWebClient_UploadStringCompleted; throw; } } return xUnityWebResponse; } } public class XUnityWebRequest { private WebHeaderCollection _headers; public string Method { get; private set; } public Uri Address { get; private set; } public string Data { get; private set; } public CookieContainer Cookies { get; set; } public WebHeaderCollection Headers { get { if (_headers == null) { _headers = new WebHeaderCollection(); } return _headers; } set { _headers = value; } } public XUnityWebRequest(string method, string address, string data) { Method = method; Address = new Uri(address); Data = data; } public XUnityWebRequest(string method, string address) { Method = method; Address = new Uri(address); Data = string.Empty; } public XUnityWebRequest(string address) { Method = "GET"; Address = new Uri(address); } } public class XUnityWebResponse : CustomYieldInstructionShim { public HttpStatusCode Code { get; private set; } public string Data { get; private set; } public WebHeaderCollection Headers { get; private set; } public CookieCollection NewCookies { get; private set; } public Exception Error { get; private set; } public override bool keepWaiting => !IsCompleted; internal bool IsCompleted { get; private set; } public XUnityWebResponse() { base.InGameTimeout = Settings.Timeout; } internal void SetCompleted(HttpStatusCode code, string data, WebHeaderCollection headers, CookieCollection newCookies, Exception error) { IsCompleted = true; Code = code; Data = data; Headers = headers; NewCookies = newCookies; Error = error; } } } namespace XUnity.AutoTranslator.Plugin.Core.Web.Internal { public delegate void XUnityDownloadStringCompletedEventHandler(object sender, XUnityDownloadStringCompletedEventArgs e); public class XUnityDownloadStringCompletedEventArgs : AsyncCompletedEventArgs { private string result; public string Result { get { RaiseExceptionIfNecessary(); return result; } } internal XUnityDownloadStringCompletedEventArgs(string result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityUploadStringCompletedEventHandler(object sender, XUnityUploadStringCompletedEventArgs e); public class XUnityUploadStringCompletedEventArgs : AsyncCompletedEventArgs { private string result; public string Result { get { RaiseExceptionIfNecessary(); return result; } } internal XUnityUploadStringCompletedEventArgs(string result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityDownloadDataCompletedEventHandler(object sender, XUnityDownloadDataCompletedEventArgs e); public class XUnityDownloadDataCompletedEventArgs : AsyncCompletedEventArgs { private byte[] result; public byte[] Result => result; internal XUnityDownloadDataCompletedEventArgs(byte[] result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityDownloadProgressChangedEventHandler(object sender, XUnityDownloadProgressChangedEventArgs e); public class XUnityDownloadProgressChangedEventArgs : ProgressChangedEventArgs { private long received; private long total; public long BytesReceived => received; public long TotalBytesToReceive => total; internal XUnityDownloadProgressChangedEventArgs(long bytesReceived, long totalBytesToReceive, object userState) : base((int)((totalBytesToReceive != -1) ? (bytesReceived * 100 / totalBytesToReceive) : 0), userState) { received = bytesReceived; total = totalBytesToReceive; } } public delegate void XUnityOpenReadCompletedEventHandler(object sender, XUnityOpenReadCompletedEventArgs e); public class XUnityOpenReadCompletedEventArgs : AsyncCompletedEventArgs { private Stream result; public Stream Result { get { RaiseExceptionIfNecessary(); return result; } } internal XUnityOpenReadCompletedEventArgs(Stream result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityOpenWriteCompletedEventHandler(object sender, XUnityOpenWriteCompletedEventArgs e); public class XUnityOpenWriteCompletedEventArgs : AsyncCompletedEventArgs { private Stream result; public Stream Result { get { RaiseExceptionIfNecessary(); return result; } } internal XUnityOpenWriteCompletedEventArgs(Stream result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityUploadDataCompletedEventHandler(object sender, XUnityUploadDataCompletedEventArgs e); public class XUnityUploadDataCompletedEventArgs : AsyncCompletedEventArgs { private byte[] result; public byte[] Result => result; internal XUnityUploadDataCompletedEventArgs(byte[] result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityUploadFileCompletedEventHandler(object sender, XUnityUploadFileCompletedEventArgs e); public class XUnityUploadFileCompletedEventArgs : AsyncCompletedEventArgs { private byte[] result; public byte[] Result => result; internal XUnityUploadFileCompletedEventArgs(byte[] result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityUploadProgressChangedEventHandler(object sender, XUnityUploadProgressChangedEventArgs e); public class XUnityUploadProgressChangedEventArgs : ProgressChangedEventArgs { private long received; private long sent; private long total_recv; private long total_send; public long BytesReceived => received; public long BytesSent => sent; public long TotalBytesToReceive => total_recv; public long TotalBytesToSend => total_send; internal XUnityUploadProgressChangedEventArgs(long bytesReceived, long totalBytesToReceive, long bytesSent, long totalBytesToSend, int progressPercentage, object userState) : base(progressPercentage, userState) { received = bytesReceived; total_recv = totalBytesToReceive; sent = bytesSent; total_send = totalBytesToSend; } } public delegate void XUnityUploadValuesCompletedEventHandler(object sender, XUnityUploadValuesCompletedEventArgs e); public class XUnityUploadValuesCompletedEventArgs : AsyncCompletedEventArgs { private byte[] result; public byte[] Result => result; internal XUnityUploadValuesCompletedEventArgs(byte[] result, Exception error, bool cancelled, object userState) : base(error, cancelled, userState) { this.result = result; } } public delegate void XUnityAsyncCompletedEventHandler(object sender, XUnityAsyncCompletedEventArgs e); public class XUnityAsyncCompletedEventArgs : EventArgs { private bool _cancelled; private Exception _error; private object _userState; public bool Cancelled => _cancelled; public Exception Error => _error; public object UserState => _userState; public XUnityAsyncCompletedEventArgs(Exception error, bool cancelled, object userState) { _error = error; _cancelled = cancelled; _userState = userState; } protected void RaiseExceptionIfNecessary() { if (_error != null) { throw new TargetInvocationException(_error); } if (_cancelled) { throw new InvalidOperationException("The operation was cancelled"); } } } public class ConnectionTrackingWebClient { private class ServicePointState { public ServicePoint ServicePoint { get; } public DateTime LastUse { get; set; } public ServicePointState(ServicePoint servicePoint) { ServicePoint = servicePoint; } } private static readonly TimeSpan MaxUnusedLifespan; private static readonly string ConnectionGroupName; private static readonly Dictionary ActiveConnections; private static readonly Dictionary TouchedServicePoints; private bool async; private Uri baseAddress; private string baseString; private ICredentials credentials; private Encoding encoding = Encoding.Default; private WebHeaderCollection headers; private static byte[] hexBytes; private bool is_busy; private IWebProxy proxy; private NameValueCollection queryString; protected WebHeaderCollection responseHeaders; private static readonly string urlEncodedCType; public string BaseAddress { get { if (baseString == null && baseAddress == null) { return string.Empty; } baseString = baseAddress.ToString(); return baseString; } set { if (value == null || value.Length == 0) { baseAddress = null; } else { baseAddress = new Uri(value); } } } public RequestCachePolicy CachePolicy { get { throw GetMustImplement(); } set { throw GetMustImplement(); } } public ICredentials Credentials { get { return credentials; } set { credentials = value; } } public Encoding Encoding { get { return encoding; } set { if (value == null) { throw new ArgumentNullException("Encoding"); } encoding = value; } } public WebHeaderCollection Headers { get { if (headers == null) { headers = new WebHeaderCollection(); } return headers; } set { headers = value; } } public bool IsBusy => is_busy; public IWebProxy Proxy { get { return proxy; } set { proxy = value; } } public NameValueCollection QueryString { get { if (queryString == null) { queryString = new NameValueCollection(); } return queryString; } set { queryString = value; } } public WebHeaderCollection ResponseHeaders => responseHeaders; public bool UseDefaultCredentials { get { throw GetMustImplement(); } set { throw GetMustImplement(); } } public event XUnityDownloadStringCompletedEventHandler DownloadStringCompleted; public event XUnityUploadStringCompletedEventHandler UploadStringCompleted; public event XUnityDownloadDataCompletedEventHandler DownloadDataCompleted; public event XUnityAsyncCompletedEventHandler DownloadFileCompleted; public event XUnityDownloadProgressChangedEventHandler DownloadProgressChanged; public event XUnityOpenReadCompletedEventHandler OpenReadCompleted; public event XUnityOpenWriteCompletedEventHandler OpenWriteCompleted; public event XUnityUploadDataCompletedEventHandler UploadDataCompleted; public event XUnityUploadFileCompletedEventHandler UploadFileCompleted; public event XUnityUploadProgressChangedEventHandler UploadProgressChanged; public event XUnityUploadValuesCompletedEventHandler UploadValuesCompleted; static ConnectionTrackingWebClient() { MaxUnusedLifespan = TimeSpan.FromSeconds(50.0); ConnectionGroupName = Guid.NewGuid().ToString(); ActiveConnections = new Dictionary(); TouchedServicePoints = new Dictionary(); hexBytes = new byte[16]; urlEncodedCType = "application/x-www-form-urlencoded"; int num = 0; int num2 = 48; while (num2 <= 57) { hexBytes[num] = (byte)num2; num2++; num++; } int num3 = 97; while (num3 <= 102) { hexBytes[num] = (byte)num3; num3++; num++; } } private static void UpdateActiveConnections(Uri address) { string text = address.Scheme + "://" + address.Host + ":" + address.Port; Uri address2 = new Uri(text); lock (ActiveConnections) { if (!ActiveConnections.TryGetValue(text, out var value)) { if (!TouchedServicePoints.TryGetValue(text, out var value2)) { value2 = ServicePointManager.FindServicePoint(address2); TouchedServicePoints.Add(text, value2); } value = new ServicePointState(value2); ActiveConnections.Add(text, value); } value.LastUse = DateTime.UtcNow; } } internal static void CheckServicePoints() { List> idleEntries = null; lock (ActiveConnections) { DateTime utcNow = DateTime.UtcNow; foreach (KeyValuePair activeConnection in ActiveConnections) { if (utcNow - activeConnection.Value.LastUse > MaxUnusedLifespan) { if (idleEntries == null) { idleEntries = new List>(); } idleEntries.Add(activeConnection); } } if (idleEntries != null) { foreach (KeyValuePair item in idleEntries) { ActiveConnections.Remove(item.Key); XuaLogger.AutoTranslator.Debug("Closing connections to endpoint '" + item.Key + "' due to inactivity."); } } } if (idleEntries == null) { return; } ThreadPool.QueueUserWorkItem(delegate { foreach (KeyValuePair item2 in idleEntries) { item2.Value.ServicePoint.CloseConnectionGroup(ConnectionGroupName); } }); } internal static void CloseServicePoints() { List> idleEntries = null; lock (ActiveConnections) { _ = DateTime.UtcNow; foreach (KeyValuePair activeConnection in ActiveConnections) { if (idleEntries == null) { idleEntries = new List>(); } idleEntries.Add(activeConnection); } if (idleEntries != null) { foreach (KeyValuePair item in idleEntries) { ActiveConnections.Remove(item.Key); XuaLogger.AutoTranslator.Debug("Closing connections to endpoint '" + item.Key + "' due to force shutdown."); } } } if (idleEntries == null) { return; } ThreadPool.QueueUserWorkItem(delegate { foreach (KeyValuePair item2 in idleEntries) { item2.Value.ServicePoint.CloseConnectionGroup(ConnectionGroupName); } }); } private void CheckBusy() { if (IsBusy) { throw new NotSupportedException("WebClient does not support conccurent I/O operations."); } } private void CompleteAsync() { lock (this) { is_busy = false; } } private Uri CreateUri(string address) { return MakeUri(address); } private Uri CreateUri(Uri address) { string query = address.Query; if (string.IsNullOrEmpty(query)) { query = GetQueryString(add_qmark: true); } if (baseAddress == null && query == null) { return address; } if (baseAddress == null) { return new Uri(address.ToString() + query, query != null); } if (query == null) { return new Uri(baseAddress, address.ToString()); } return new Uri(baseAddress, address.ToString() + query, query != null); } private string DetermineMethod(Uri address, string method, bool is_upload) { if (method != null) { return method; } if (address.Scheme == Uri.UriSchemeFtp) { if (is_upload) { return "STOR"; } return "RETR"; } if (is_upload) { return "POST"; } return "GET"; } public byte[] DownloadData(string address) { if (address == null) { throw new ArgumentNullException("address"); } return DownloadData(CreateUri(address)); } public byte[] DownloadData(Uri address) { if (address == null) { throw new ArgumentNullException("address"); } try { SetBusy(); async = false; return DownloadDataCore(address, null); } finally { is_busy = false; } } public void DownloadDataAsync(Uri address) { DownloadDataAsync(address, null); } public void DownloadDataAsync(Uri address, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[2] { address, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { byte[] result = DownloadDataCore((Uri)array[0], array[1]); OnDownloadDataCompleted(new XUnityDownloadDataCompletedEventArgs(result, null, cancelled: false, array[1])); } catch (ThreadInterruptedException) { OnDownloadDataCompleted(new XUnityDownloadDataCompletedEventArgs(null, null, cancelled: true, array[1])); throw; } catch (Exception error) { OnDownloadDataCompleted(new XUnityDownloadDataCompletedEventArgs(null, error, cancelled: false, array[1])); } }, state2); } } private byte[] DownloadDataCore(Uri address, object userToken) { WebRequest webRequest = null; try { webRequest = SetupRequest(address); using WebResponse webResponse = GetWebResponse(webRequest); using Stream stream = webResponse.GetResponseStream(); byte[] result = ReadAll(stream, (int)webResponse.ContentLength, userToken); stream.Close(); webResponse.Close(); return result; } catch (ThreadInterruptedException) { webRequest?.Abort(); throw; } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } } public void DownloadFile(string address, string fileName) { if (address == null) { throw new ArgumentNullException("address"); } DownloadFile(CreateUri(address), fileName); } public void DownloadFile(Uri address, string fileName) { if (address == null) { throw new ArgumentNullException("address"); } if (fileName == null) { throw new ArgumentNullException("fileName"); } try { SetBusy(); async = false; DownloadFileCore(address, fileName, null); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void DownloadFileAsync(Uri address, string fileName) { DownloadFileAsync(address, fileName, null); } public void DownloadFileAsync(Uri address, string fileName, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } if (fileName == null) { throw new ArgumentNullException("fileName"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[3] { address, fileName, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { DownloadFileCore((Uri)array[0], (string)array[1], array[2]); OnDownloadFileCompleted(new XUnityAsyncCompletedEventArgs(null, cancelled: false, array[2])); } catch (ThreadInterruptedException) { OnDownloadFileCompleted(new XUnityAsyncCompletedEventArgs(null, cancelled: true, array[2])); } catch (Exception error) { OnDownloadFileCompleted(new XUnityAsyncCompletedEventArgs(error, cancelled: false, array[2])); } }, state2); } } private void DownloadFileCore(Uri address, string fileName, object userToken) { WebRequest webRequest = null; FileStream fileStream = new FileStream(fileName, FileMode.Create); try { webRequest = SetupRequest(address); using WebResponse webResponse = GetWebResponse(webRequest); using Stream stream = webResponse.GetResponseStream(); int num = (int)webResponse.ContentLength; int num2 = ((num > -1 && num <= 32768) ? num : 32768); byte[] buffer = new byte[num2]; int num3 = 0; long num4 = 0L; while ((num3 = stream.Read(buffer, 0, num2)) != 0) { if (async) { num4 += num3; OnDownloadProgressChanged(new XUnityDownloadProgressChangedEventArgs(num4, webResponse.ContentLength, userToken)); } fileStream.Write(buffer, 0, num3); } stream.Close(); webResponse.Close(); } catch (ThreadInterruptedException) { webRequest?.Abort(); throw; } finally { fileStream?.Dispose(); } } public string DownloadString(string address) { if (address == null) { throw new ArgumentNullException("address"); } return encoding.GetString(DownloadData(CreateUri(address))); } public string DownloadString(Uri address) { if (address == null) { throw new ArgumentNullException("address"); } return encoding.GetString(DownloadData(CreateUri(address))); } public void DownloadStringAsync(Uri address) { DownloadStringAsync(address, null); } public void DownloadStringAsync(Uri address, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[2] { address, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { string @string = encoding.GetString(DownloadDataCore((Uri)array[0], array[1])); OnDownloadStringCompleted(new XUnityDownloadStringCompletedEventArgs(@string, null, cancelled: false, array[1])); } catch (ThreadInterruptedException) { OnDownloadStringCompleted(new XUnityDownloadStringCompletedEventArgs(null, null, cancelled: true, array[1])); } catch (Exception error) { OnDownloadStringCompleted(new XUnityDownloadStringCompletedEventArgs(null, error, cancelled: false, array[1])); } }, state2); } } private static Exception GetMustImplement() { return new NotImplementedException(); } private string GetQueryString(bool add_qmark) { if (queryString == null || queryString.Count == 0) { return null; } StringBuilder stringBuilder = new StringBuilder(); if (add_qmark) { stringBuilder.Append('?'); } foreach (string item in queryString) { stringBuilder.AppendFormat("{0}={1}&", item, UrlEncode(queryString[item])); } if (stringBuilder.Length != 0) { stringBuilder.Length--; } if (stringBuilder.Length == 0) { return null; } return stringBuilder.ToString(); } protected virtual WebRequest GetWebRequest(Uri address) { WebRequest result = WebRequest.Create(address); UpdateActiveConnections(address); return result; } protected virtual WebResponse GetWebResponse(WebRequest request) { WebResponse response = request.GetResponse(); responseHeaders = response.Headers; UpdateActiveConnections(request.RequestUri); return response; } protected virtual WebResponse GetWebResponse(WebRequest request, IAsyncResult result) { WebResponse webResponse = request.EndGetResponse(result); responseHeaders = webResponse.Headers; UpdateActiveConnections(request.RequestUri); return webResponse; } private Uri MakeUri(string path) { string text = GetQueryString(add_qmark: true); if (baseAddress == null && text == null) { try { return new Uri(path); } catch (ArgumentNullException) { path = Path.GetFullPath(path); return new Uri("file://" + path); } catch (UriFormatException) { path = Path.GetFullPath(path); return new Uri("file://" + path); } } if (baseAddress == null) { return new Uri(path + text, text != null); } if (text == null) { return new Uri(baseAddress, path); } return new Uri(baseAddress, path + text, text != null); } protected virtual void OnDownloadDataCompleted(XUnityDownloadDataCompletedEventArgs args) { CompleteAsync(); if (this.DownloadDataCompleted != null) { this.DownloadDataCompleted(this, args); } } protected virtual void OnDownloadFileCompleted(XUnityAsyncCompletedEventArgs args) { CompleteAsync(); if (this.DownloadFileCompleted != null) { this.DownloadFileCompleted(this, args); } } protected virtual void OnDownloadProgressChanged(XUnityDownloadProgressChangedEventArgs e) { if (this.DownloadProgressChanged != null) { this.DownloadProgressChanged(this, e); } } protected virtual void OnDownloadStringCompleted(XUnityDownloadStringCompletedEventArgs args) { CompleteAsync(); if (this.DownloadStringCompleted != null) { this.DownloadStringCompleted(this, args); } } protected virtual void OnOpenReadCompleted(XUnityOpenReadCompletedEventArgs args) { CompleteAsync(); if (this.OpenReadCompleted != null) { this.OpenReadCompleted(this, args); } } protected virtual void OnOpenWriteCompleted(XUnityOpenWriteCompletedEventArgs args) { CompleteAsync(); if (this.OpenWriteCompleted != null) { this.OpenWriteCompleted(this, args); } } protected virtual void OnUploadDataCompleted(XUnityUploadDataCompletedEventArgs args) { CompleteAsync(); if (this.UploadDataCompleted != null) { this.UploadDataCompleted(this, args); } } protected virtual void OnUploadFileCompleted(XUnityUploadFileCompletedEventArgs args) { CompleteAsync(); if (this.UploadFileCompleted != null) { this.UploadFileCompleted(this, args); } } protected virtual void OnUploadProgressChanged(XUnityUploadProgressChangedEventArgs e) { if (this.UploadProgressChanged != null) { this.UploadProgressChanged(this, e); } } protected virtual void OnUploadStringCompleted(XUnityUploadStringCompletedEventArgs args) { CompleteAsync(); if (this.UploadStringCompleted != null) { this.UploadStringCompleted(this, args); } } protected virtual void OnUploadValuesCompleted(XUnityUploadValuesCompletedEventArgs args) { CompleteAsync(); if (this.UploadValuesCompleted != null) { this.UploadValuesCompleted(this, args); } } public Stream OpenRead(string address) { if (address == null) { throw new ArgumentNullException("address"); } return OpenRead(CreateUri(address)); } public Stream OpenRead(Uri address) { if (address == null) { throw new ArgumentNullException("address"); } WebRequest webRequest = null; try { SetBusy(); async = false; webRequest = SetupRequest(address); return GetWebResponse(webRequest).GetResponseStream(); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void OpenReadAsync(Uri address) { OpenReadAsync(address, null); } public void OpenReadAsync(Uri address, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[2] { address, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; WebRequest webRequest = null; try { webRequest = SetupRequest((Uri)array[0]); Stream responseStream = GetWebResponse(webRequest).GetResponseStream(); OnOpenReadCompleted(new XUnityOpenReadCompletedEventArgs(responseStream, null, cancelled: false, array[1])); } catch (ThreadInterruptedException) { webRequest?.Abort(); OnOpenReadCompleted(new XUnityOpenReadCompletedEventArgs(null, null, cancelled: true, array[1])); } catch (Exception error) { OnOpenReadCompleted(new XUnityOpenReadCompletedEventArgs(null, error, cancelled: false, array[1])); } }, state2); } } public Stream OpenWrite(string address) { if (address == null) { throw new ArgumentNullException("address"); } return OpenWrite(CreateUri(address)); } public Stream OpenWrite(Uri address) { return OpenWrite(address, null); } public Stream OpenWrite(string address, string method) { if (address == null) { throw new ArgumentNullException("address"); } return OpenWrite(CreateUri(address), method); } public Stream OpenWrite(Uri address, string method) { if (address == null) { throw new ArgumentNullException("address"); } try { SetBusy(); async = false; return SetupRequest(address, method, is_upload: true).GetRequestStream(); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void OpenWriteAsync(Uri address) { OpenWriteAsync(address, null); } public void OpenWriteAsync(Uri address, string method) { OpenWriteAsync(address, method, null); } public void OpenWriteAsync(Uri address, string method, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[3] { address, method, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; WebRequest webRequest = null; try { webRequest = SetupRequest((Uri)array[0], (string)array[1], is_upload: true); Stream requestStream = webRequest.GetRequestStream(); OnOpenWriteCompleted(new XUnityOpenWriteCompletedEventArgs(requestStream, null, cancelled: false, array[2])); } catch (ThreadInterruptedException) { webRequest?.Abort(); OnOpenWriteCompleted(new XUnityOpenWriteCompletedEventArgs(null, null, cancelled: true, array[2])); } catch (Exception error) { OnOpenWriteCompleted(new XUnityOpenWriteCompletedEventArgs(null, error, cancelled: false, array[2])); } }, state2); } } private byte[] ReadAll(Stream stream, int length, object userToken) { MemoryStream memoryStream = null; bool flag = length == -1; int num = ((!flag) ? length : 8192); if (flag) { memoryStream = new MemoryStream(); } int num2 = 0; int num3 = 0; byte[] array = new byte[num]; while ((num2 = stream.Read(array, num3, num)) != 0) { if (flag) { memoryStream.Write(array, 0, num2); continue; } num3 += num2; num -= num2; } if (flag) { return memoryStream.ToArray(); } return array; } private void SetBusy() { lock (this) { CheckBusy(); is_busy = true; } } private WebRequest SetupRequest(Uri uri) { WebRequest webRequest = GetWebRequest(uri); webRequest.ConnectionGroupName = ConnectionGroupName; if (Proxy != null) { webRequest.Proxy = Proxy; } webRequest.Credentials = credentials; if (headers != null && headers.Count != 0 && webRequest is HttpWebRequest) { HttpWebRequest httpWebRequest = (HttpWebRequest)webRequest; string text = headers["Expect"]; string text2 = headers["Content-Type"]; string text3 = headers["Accept"]; string text4 = headers["Connection"]; string text5 = headers["User-Agent"]; string text6 = headers["Referer"]; headers.Remove("Expect"); headers.Remove("Content-Type"); headers.Remove("Accept"); headers.Remove("Connection"); headers.Remove("Referer"); headers.Remove("User-Agent"); webRequest.Headers = headers; if (text != null && text.Length > 0) { httpWebRequest.Expect = text; } if (text3 != null && text3.Length > 0) { httpWebRequest.Accept = text3; } if (text2 != null && text2.Length > 0) { httpWebRequest.ContentType = text2; } if (text4 != null && text4.Length > 0) { httpWebRequest.Connection = text4; } if (text5 != null && text5.Length > 0) { httpWebRequest.UserAgent = text5; } if (text6 != null && text6.Length > 0) { httpWebRequest.Referer = text6; } } responseHeaders = null; return webRequest; } private WebRequest SetupRequest(Uri uri, string method, bool is_upload) { WebRequest webRequest = SetupRequest(uri); webRequest.Method = DetermineMethod(uri, method, is_upload); return webRequest; } public byte[] UploadData(string address, byte[] data) { if (address == null) { throw new ArgumentNullException("address"); } return UploadData(CreateUri(address), data); } public byte[] UploadData(Uri address, byte[] data) { return UploadData(address, null, data); } public byte[] UploadData(string address, string method, byte[] data) { if (address == null) { throw new ArgumentNullException("address"); } return UploadData(CreateUri(address), method, data); } public byte[] UploadData(Uri address, string method, byte[] data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } try { SetBusy(); async = false; return UploadDataCore(address, method, data, null); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void UploadDataAsync(Uri address, byte[] data) { UploadDataAsync(address, null, data); } public void UploadDataAsync(Uri address, string method, byte[] data) { UploadDataAsync(address, method, data, null); } public void UploadDataAsync(Uri address, string method, byte[] data, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[4] { address, method, data, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { byte[] result = UploadDataCore((Uri)array[0], (string)array[1], (byte[])array[2], array[3]); OnUploadDataCompleted(new XUnityUploadDataCompletedEventArgs(result, null, cancelled: false, array[3])); } catch (ThreadInterruptedException) { OnUploadDataCompleted(new XUnityUploadDataCompletedEventArgs(null, null, cancelled: true, array[3])); } catch (Exception error) { OnUploadDataCompleted(new XUnityUploadDataCompletedEventArgs(null, error, cancelled: false, array[3])); } }, state2); } } private byte[] UploadDataCore(Uri address, string method, byte[] data, object userToken) { WebRequest webRequest = SetupRequest(address, method, is_upload: true); try { int num = data.Length; webRequest.ContentLength = num; using (Stream stream = webRequest.GetRequestStream()) { stream.Write(data, 0, num); } using WebResponse webResponse = GetWebResponse(webRequest); using Stream stream2 = webResponse.GetResponseStream(); byte[] result = ReadAll(stream2, (int)webResponse.ContentLength, userToken); stream2.Close(); webResponse.Close(); return result; } catch (ThreadInterruptedException) { webRequest?.Abort(); throw; } } public byte[] UploadFile(string address, string fileName) { if (address == null) { throw new ArgumentNullException("address"); } return UploadFile(CreateUri(address), fileName); } public byte[] UploadFile(Uri address, string fileName) { return UploadFile(address, null, fileName); } public byte[] UploadFile(string address, string method, string fileName) { return UploadFile(CreateUri(address), method, fileName); } public byte[] UploadFile(Uri address, string method, string fileName) { if (address == null) { throw new ArgumentNullException("address"); } if (fileName == null) { throw new ArgumentNullException("fileName"); } try { SetBusy(); async = false; return UploadFileCore(address, method, fileName, null); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void UploadFileAsync(Uri address, string fileName) { UploadFileAsync(address, null, fileName); } public void UploadFileAsync(Uri address, string method, string fileName) { UploadFileAsync(address, method, fileName, null); } public void UploadFileAsync(Uri address, string method, string fileName, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } if (fileName == null) { throw new ArgumentNullException("fileName"); } lock (this) { SetBusy(); async = true; object[] state2 = new object[4] { address, method, fileName, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { byte[] result = UploadFileCore((Uri)array[0], (string)array[1], (string)array[2], array[3]); OnUploadFileCompleted(new XUnityUploadFileCompletedEventArgs(result, null, cancelled: false, array[3])); } catch (ThreadInterruptedException) { OnUploadFileCompleted(new XUnityUploadFileCompletedEventArgs(null, null, cancelled: true, array[3])); } catch (Exception error) { OnUploadFileCompleted(new XUnityUploadFileCompletedEventArgs(null, error, cancelled: false, array[3])); } }, state2); } } private byte[] UploadFileCore(Uri address, string method, string fileName, object userToken) { string text = Headers["Content-Type"]; if (text != null) { if (text.ToLower().StartsWith("multipart/")) { throw new WebException("Content-Type cannot be set to a multipart type for this request."); } } else { text = "application/octet-stream"; } string text2 = "------------" + DateTime.Now.Ticks.ToString("x"); Headers["Content-Type"] = $"multipart/form-data; boundary={text2}"; Stream stream = null; Stream stream2 = null; byte[] array = null; fileName = Path.GetFullPath(fileName); WebRequest webRequest = null; try { stream2 = File.OpenRead(fileName); webRequest = SetupRequest(address, method, is_upload: true); stream = webRequest.GetRequestStream(); byte[] bytes = Encoding.ASCII.GetBytes("--" + text2 + "\r\n"); stream.Write(bytes, 0, bytes.Length); string s = $"Content-Disposition: form-data; name=\"file\"; filename=\"{Path.GetFileName(fileName)}\"\r\nContent-Type: {text}\r\n\r\n"; byte[] bytes2 = Encoding.UTF8.GetBytes(s); stream.Write(bytes2, 0, bytes2.Length); byte[] buffer = new byte[4096]; int count; while ((count = stream2.Read(buffer, 0, 4096)) != 0) { stream.Write(buffer, 0, count); } stream.WriteByte(13); stream.WriteByte(10); stream.Write(bytes, 0, bytes.Length); stream.Close(); stream = null; using WebResponse webResponse = GetWebResponse(webRequest); using Stream stream3 = webResponse.GetResponseStream(); array = ReadAll(stream3, (int)webResponse.ContentLength, userToken); stream3.Close(); webResponse.Close(); return array; } catch (ThreadInterruptedException) { webRequest?.Abort(); throw; } finally { stream2?.Close(); stream?.Close(); } } public string UploadString(string address, string data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } byte[] bytes = UploadData(address, encoding.GetBytes(data)); return encoding.GetString(bytes); } public string UploadString(Uri address, string data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } byte[] bytes = UploadData(address, encoding.GetBytes(data)); return encoding.GetString(bytes); } public string UploadString(string address, string method, string data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } byte[] bytes = UploadData(address, method, encoding.GetBytes(data)); return encoding.GetString(bytes); } public string UploadString(Uri address, string method, string data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } byte[] bytes = UploadData(address, method, encoding.GetBytes(data)); return encoding.GetString(bytes); } public void UploadStringAsync(Uri address, string data) { UploadStringAsync(address, null, data); } public void UploadStringAsync(Uri address, string method, string data) { UploadStringAsync(address, method, data, null); } public void UploadStringAsync(Uri address, string method, string data, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } lock (this) { CheckBusy(); async = true; object[] state2 = new object[4] { address, method, data, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { string result = UploadString((Uri)array[0], (string)array[1], (string)array[2]); OnUploadStringCompleted(new XUnityUploadStringCompletedEventArgs(result, null, cancelled: false, array[3])); } catch (ThreadInterruptedException) { OnUploadStringCompleted(new XUnityUploadStringCompletedEventArgs(null, null, cancelled: true, array[3])); } catch (Exception error) { OnUploadStringCompleted(new XUnityUploadStringCompletedEventArgs(null, error, cancelled: false, array[3])); } }, state2); } } public byte[] UploadValues(string address, NameValueCollection data) { if (address == null) { throw new ArgumentNullException("address"); } return UploadValues(CreateUri(address), data); } public byte[] UploadValues(Uri address, NameValueCollection data) { return UploadValues(address, null, data); } public byte[] UploadValues(string address, string method, NameValueCollection data) { if (address == null) { throw new ArgumentNullException("address"); } return UploadValues(CreateUri(address), method, data); } public byte[] UploadValues(Uri address, string method, NameValueCollection data) { if (address == null) { throw new ArgumentNullException("address"); } if (data == null) { throw new ArgumentNullException("data"); } try { SetBusy(); async = false; return UploadValuesCore(address, method, data, null); } catch (WebException) { throw; } catch (Exception innerException) { throw new WebException("An error occurred performing a WebClient request.", innerException); } finally { is_busy = false; } } public void UploadValuesAsync(Uri address, NameValueCollection values) { UploadValuesAsync(address, null, values); } public void UploadValuesAsync(Uri address, string method, NameValueCollection values) { UploadValuesAsync(address, method, values, null); } public void UploadValuesAsync(Uri address, string method, NameValueCollection values, object userToken) { if (address == null) { throw new ArgumentNullException("address"); } if (values == null) { throw new ArgumentNullException("values"); } lock (this) { CheckBusy(); async = true; object[] state2 = new object[4] { address, method, values, userToken }; ThreadPool.QueueUserWorkItem(delegate(object state) { object[] array = (object[])state; try { byte[] result = UploadValuesCore((Uri)array[0], (string)array[1], (NameValueCollection)array[2], array[3]); OnUploadValuesCompleted(new XUnityUploadValuesCompletedEventArgs(result, null, cancelled: false, array[3])); } catch (ThreadInterruptedException) { OnUploadValuesCompleted(new XUnityUploadValuesCompletedEventArgs(null, null, cancelled: true, array[3])); } catch (Exception error) { OnUploadValuesCompleted(new XUnityUploadValuesCompletedEventArgs(null, error, cancelled: false, array[3])); } }, state2); } } private byte[] UploadValuesCore(Uri uri, string method, NameValueCollection data, object userToken) { string text = Headers["Content-Type"]; if (text != null && string.Compare(text, urlEncodedCType, ignoreCase: true, CultureInfo.InvariantCulture) != 0) { throw new WebException("Content-Type header cannot be changed from its default value for this request."); } Headers["Content-Type"] = urlEncodedCType; WebRequest webRequest = SetupRequest(uri, method, is_upload: true); try { MemoryStream memoryStream = new MemoryStream(); foreach (string datum in data) { byte[] bytes = Encoding.UTF8.GetBytes(datum); UrlEncodeAndWrite(memoryStream, bytes); memoryStream.WriteByte(61); bytes = Encoding.UTF8.GetBytes(data[datum]); UrlEncodeAndWrite(memoryStream, bytes); memoryStream.WriteByte(38); } int num = (int)memoryStream.Length; if (num > 0) { memoryStream.SetLength(--num); } byte[] buffer = memoryStream.GetBuffer(); webRequest.ContentLength = num; using (Stream stream = webRequest.GetRequestStream()) { stream.Write(buffer, 0, num); } memoryStream.Close(); using WebResponse webResponse = GetWebResponse(webRequest); using Stream stream2 = webResponse.GetResponseStream(); byte[] result = ReadAll(stream2, (int)webResponse.ContentLength, userToken); stream2.Close(); webResponse.Close(); return result; } catch (ThreadInterruptedException) { webRequest.Abort(); throw; } } private string UrlEncode(string str) { StringBuilder stringBuilder = new StringBuilder(); int length = str.Length; for (int i = 0; i < length; i++) { char c = str[i]; if (c == ' ') { stringBuilder.Append('+'); } else if ((c < '0' && c != '-' && c != '.') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a' && c != '_') || c > 'z') { stringBuilder.Append('%'); int num = (int)c >> 4; stringBuilder.Append((char)hexBytes[num]); num = c & 0xF; stringBuilder.Append((char)hexBytes[num]); } else { stringBuilder.Append(c); } } return stringBuilder.ToString(); } private static void UrlEncodeAndWrite(Stream stream, byte[] bytes) { if (bytes == null) { return; } int num = bytes.Length; if (num == 0) { return; } for (int i = 0; i < num; i++) { char c = (char)bytes[i]; if (c == ' ') { stream.WriteByte(43); } else if ((c < '0' && c != '-' && c != '.') || (c < 'A' && c > '9') || (c > 'Z' && c < 'a' && c != '_') || c > 'z') { stream.WriteByte(37); int num2 = (int)c >> 4; stream.WriteByte(hexBytes[num2]); num2 = c & 0xF; stream.WriteByte(hexBytes[num2]); } else { stream.WriteByte((byte)c); } } } } } namespace XUnity.AutoTranslator.Plugin.Core.Utilties { internal class IndentedTextWriter { private readonly TextWriter _writer; private readonly char _indent; public int Indent { get; set; } public IndentedTextWriter(TextWriter writer, char indent) { _writer = writer; _indent = indent; } public void WriteLine(string line) { _writer.Write(new string(_indent, Indent)); _writer.WriteLine(line); } } } namespace XUnity.AutoTranslator.Plugin.Core.UI { internal class AggregatedTranslationViewModel { private List _translations; private TranslationAggregatorViewModel _parent; private float? _started; public List AggregatedTranslations { get; set; } public IEnumerable DefaultTranslations => _translations.Select((Translation x) => x.TranslatedText); public IEnumerable OriginalTexts => _translations.Select((Translation x) => x.OriginalText); public AggregatedTranslationViewModel(TranslationAggregatorViewModel parent, List translations) { _parent = parent; _translations = translations; AggregatedTranslations = parent.AvailableTranslators.Select((TranslatorViewModel x) => new IndividualTranslatorTranslationViewModel(x, new IndividualTranslationViewModel(x, translations.Select((Translation y) => new Translation(y.OriginalText, null)).ToList()))).ToList(); } public void CopyDefaultTranslationToClipboard() { ClipboardHelper.CopyToClipboard(DefaultTranslations, 32767); } public void CopyOriginalTextToClipboard() { ClipboardHelper.CopyToClipboard(OriginalTexts, 32767); } public void Update() { if (!_parent.IsShown) { return; } if (_parent.Manager.OngoingTranslations == 0 && _parent.Manager.UnstartedTranslations == 0) { if (_started.HasValue) { if (Time.realtimeSinceStartup - _started.Value > 1f) { foreach (IndividualTranslatorTranslationViewModel aggregatedTranslation in AggregatedTranslations) { aggregatedTranslation.Translation.StartTranslations(); } } } else { _started = Time.realtimeSinceStartup; } } foreach (IndividualTranslatorTranslationViewModel aggregatedTranslation2 in AggregatedTranslations) { aggregatedTranslation2.Translation.CheckCompleted(); } } } internal class ButtonViewModel { public GUIContent Text { get; set; } public Action OnClicked { get; set; } public Func CanClick { get; set; } public ButtonViewModel(string text, string tooltip, Action onClicked, Func canClick) { Text = GUIUtil.CreateContent(text, tooltip); OnClicked = onClicked; CanClick = canClick; } } internal class DropdownGUI where TDropdownOptionViewModel : DropdownOptionViewModel where TSelection : class { private const float MaxHeight = 105f; private GUIContent _noSelection; private GUIContent _unselect; private DropdownViewModel _viewModel; private float _x; private float _y; private float _width; private bool _isShown; private Vector2 _scrollPosition; private bool _supportsScrollView = true; public DropdownGUI(float x, float y, float width, DropdownViewModel viewModel) { _x = x; _y = y; _width = width; _noSelection = GUIUtil.CreateContent(viewModel.NoSelection, viewModel.NoSelectionTooltip); _unselect = GUIUtil.CreateContent(viewModel.Unselect, viewModel.UnselectTooltip); _viewModel = viewModel; } public bool OnGUI(bool enabled) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) bool enabled2 = GUI.enabled; try { GUI.enabled = enabled; bool num = GUI.Button(GUIUtil.R(_x, _y, _width, 21f), _viewModel.CurrentSelection?.Text ?? _noSelection, _isShown ? GUIUtil.NoMarginButtonPressedStyle : GUI.skin.button); if (num) { _isShown = !_isShown; } if (!enabled) { _isShown = false; } if (_isShown) { ShowDropdown(_x, _y + 21f, _width, GUI.skin.button); } if (!num && Event.current.isMouse) { _isShown = false; } return _isShown; } finally { GUI.enabled = enabled2; } } private void ShowDropdown(float x, float y, float width, GUIStyle buttonStyle) { //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) GUILayout.BeginArea(GUIUtil.R(x, y, width, (_supportsScrollView && (float)_viewModel.Options.Count * 21f > 105f) ? 105f : ((float)_viewModel.Options.Count * 21f)), GUIUtil.NoSpacingBoxStyle); try { if (_supportsScrollView) { _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, GUIStyle.none); } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "GUILayout.BeginScrollView not supported. Proceeding without..."); _supportsScrollView = false; } GUIStyle val = ((_viewModel.CurrentSelection == null) ? GUIUtil.NoMarginButtonPressedStyle : GUIUtil.NoMarginButtonStyle); if (GUILayout.Button(_unselect, val, ArrayHelper.Null())) { _viewModel.Select(null); _isShown = false; } foreach (TDropdownOptionViewModel option in _viewModel.Options) { val = (option.IsSelected() ? GUIUtil.NoMarginButtonPressedStyle : GUIUtil.NoMarginButtonStyle); GUI.enabled = option?.IsEnabled() ?? true; if (GUILayout.Button(option.Text, val, ArrayHelper.Null())) { _viewModel.Select(option); _isShown = false; } GUI.enabled = true; } if (_supportsScrollView) { GUILayout.EndScrollView(); } GUILayout.EndArea(); } } internal class DropdownViewModel where TDropdownOptionViewModel : DropdownOptionViewModel where TSelection : class { private Action _onSelected; public TDropdownOptionViewModel CurrentSelection { get; set; } public List Options { get; set; } public string NoSelection { get; } public string NoSelectionTooltip { get; } public string Unselect { get; } public string UnselectTooltip { get; } public DropdownViewModel(string noSelection, string noSelectionTooltip, string unselect, string unselectTooltip, IEnumerable options, Action onSelected) { NoSelection = noSelection; NoSelectionTooltip = noSelectionTooltip; Unselect = unselect; UnselectTooltip = unselectTooltip; _onSelected = onSelected; Options = new List(); foreach (TDropdownOptionViewModel option in options) { if (option.IsSelected()) { CurrentSelection = option; } Options.Add(option); } } public void Select(TDropdownOptionViewModel option) { if (option == null || !option.IsSelected()) { CurrentSelection = option; Action onSelected = _onSelected; if (onSelected != null) { TDropdownOptionViewModel currentSelection = CurrentSelection; onSelected((currentSelection != null) ? currentSelection.Selection : null); } } } } internal class DropdownOptionViewModel { public virtual GUIContent Text { get; set; } public Func IsEnabled { get; set; } public Func IsSelected { get; set; } public TSelection Selection { get; set; } public DropdownOptionViewModel(string text, Func isSelected, Func isEnabled, TSelection selection) { Text = GUIUtil.CreateContent(text); IsSelected = isSelected; IsEnabled = isEnabled; Selection = selection; } } internal class TranslatorDropdownOptionViewModel : DropdownOptionViewModel { private GUIContent _selected; private GUIContent _normal; private GUIContent _disabled; public override GUIContent Text { get { if (base.Selection.Error != null) { return _disabled; } if (base.IsSelected()) { return _selected; } return _normal; } } public TranslatorDropdownOptionViewModel(bool fallback, Func isSelected, TranslationEndpointManager selection) : base(selection.Endpoint.FriendlyName, isSelected, (Func)(() => selection.Error == null), selection) { if (fallback) { _selected = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "CURRENT FALLBACK TRANSLATOR\n" + selection.Endpoint.FriendlyName + " is the currently selected fallback translator that will be used to perform translations when the primary translator fails."); _disabled = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "CANNOT SELECT FALLBACK TRANSLATOR\n" + selection.Endpoint.FriendlyName + " cannot be selected because the initialization failed. " + selection.Error?.Message); _normal = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "SELECT FALLBACK TRANSLATOR\n" + selection.Endpoint.FriendlyName + " will be selected as fallback translator."); } else { _selected = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "CURRENT TRANSLATOR\n" + selection.Endpoint.FriendlyName + " is the currently selected translator that will be used to perform translations."); _disabled = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "CANNOT SELECT TRANSLATOR\n" + selection.Endpoint.FriendlyName + " cannot be selected because the initialization failed. " + selection.Error?.Message); _normal = GUIUtil.CreateContent(selection.Endpoint.FriendlyName, "SELECT TRANSLATOR\n" + selection.Endpoint.FriendlyName + " will be selected as translator."); } } } internal static class GUIUtil { public const float WindowTitleClearance = 10f; public const float ComponentSpacing = 10f; public const float HalfComponentSpacing = 5f; public const float LabelWidth = 60f; public const float LabelHeight = 21f; public const float RowHeight = 21f; public static GUIContent none = new GUIContent(""); public static readonly RectOffset Empty = new RectOffset { left = 0, right = 0, top = 0, bottom = 0 }; public static readonly GUIStyle LabelTranslation = CopyStyle(GUI.skin.label, delegate(GUIStyle style) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Expected O, but got Unknown style.richText = false; style.margin = new RectOffset { left = GUI.skin.label.margin.left, right = GUI.skin.label.margin.right, top = 0, bottom = 0 }; style.padding = new RectOffset { left = GUI.skin.label.padding.left, right = GUI.skin.label.padding.right, top = 2, bottom = 3 }; }); public static readonly GUIStyle LabelCenter = CopyStyle(GUI.skin.label, delegate(GUIStyle style) { style.alignment = (TextAnchor)1; style.richText = true; }); public static readonly GUIStyle LabelRight = CopyStyle(GUI.skin.label, delegate(GUIStyle style) { style.alignment = (TextAnchor)2; }); public static readonly GUIStyle LabelRich = CopyStyle(GUI.skin.label, delegate(GUIStyle style) { style.richText = true; }); public static readonly GUIStyle NoMarginButtonStyle = CopyStyle(GUI.skin.button, delegate(GUIStyle style) { style.margin = Empty; }); public static readonly GUIStyle NoMarginButtonPressedStyle = CopyStyle(GUI.skin.button, delegate(GUIStyle style) { style.margin = Empty; style.onNormal = GUI.skin.button.onActive; style.onFocused = GUI.skin.button.onActive; style.onHover = GUI.skin.button.onActive; style.normal = GUI.skin.button.onActive; style.focused = GUI.skin.button.onActive; style.hover = GUI.skin.button.onActive; }); public static readonly GUIStyle NoSpacingBoxStyle = CopyStyle(GUI.skin.box, delegate(GUIStyle style) { style.margin = Empty; style.padding = Empty; }); public static GUIStyle WindowBackgroundStyle = new GUIStyle { normal = new GUIStyleState { background = CreateBackgroundTexture() } }; public static bool IsAnyMouseButtonOrScrollWheelDownSafe { get { if (!UnityFeatures.SupportsMouseScrollDelta) { return IsAnyMouseButtonOrScrollWheelDownLegacy; } return IsAnyMouseButtonOrScrollWheelDown; } } public static bool IsAnyMouseButtonOrScrollWheelDownLegacy { get { if (!UnityInput.Current.GetMouseButtonDown(0) && !UnityInput.Current.GetMouseButtonDown(1)) { return UnityInput.Current.GetMouseButtonDown(2); } return true; } } public static bool IsAnyMouseButtonOrScrollWheelDown { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (UnityInput.Current.mouseScrollDelta.y == 0f && !UnityInput.Current.GetMouseButtonDown(0) && !UnityInput.Current.GetMouseButtonDown(1)) { return UnityInput.Current.GetMouseButtonDown(2); } return true; } } public static bool IsAnyMouseButtonOrScrollWheelSafe { get { if (!UnityFeatures.SupportsMouseScrollDelta) { return IsAnyMouseButtonOrScrollWheelLegacy; } return IsAnyMouseButtonOrScrollWheel; } } public static bool IsAnyMouseButtonOrScrollWheelLegacy { get { if (!UnityInput.Current.GetMouseButton(0) && !UnityInput.Current.GetMouseButton(1)) { return UnityInput.Current.GetMouseButton(2); } return true; } } public static bool IsAnyMouseButtonOrScrollWheel { get { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (UnityInput.Current.mouseScrollDelta.y == 0f && !UnityInput.Current.GetMouseButton(0) && !UnityInput.Current.GetMouseButton(1)) { return UnityInput.Current.GetMouseButton(2); } return true; } } public static GUIStyle CopyStyle(GUIStyle other, Action setProperties) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown GUIStyle val = new GUIStyle(other); setProperties(val); return val; } public static GUIContent CreateContent(string text) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown return new GUIContent(text); } public static GUIContent CreateContent(string text, string tooltip) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown return new GUIContent(text, tooltip); } public static Rect R(float x, float y, float width, float height) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) return new Rect(x, y, width, height); } private static Texture2D CreateBackgroundTexture() { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown //IL_0037: Expected O, but got Unknown Texture2D val = new Texture2D(1, 1, (TextureFormat)5, false); val.SetPixel(0, 0, new Color(0.6f, 0.6f, 0.6f, 1f)); val.Apply(); Object.DontDestroyOnLoad((Object)val); return val; } public static GUIStyle GetWindowBackgroundStyle() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //IL_0036: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)WindowBackgroundStyle.normal.background)) { WindowBackgroundStyle = new GUIStyle { normal = new GUIStyleState { background = CreateBackgroundTexture() } }; } return WindowBackgroundStyle; } } internal class IndividualTranslationViewModel { private string[] _notTranslated = new string[1] { "Not translated yet." }; private string[] _requestingTranslation = new string[1] { "Requesting translation..." }; private List _translations; private TranslatorViewModel _translator; private bool _hasStartedTranslation; private bool _isTranslated; public IEnumerable Translations { get { if (_isTranslated) { return _translations.Select((Translation x) => x.TranslatedText); } if (_hasStartedTranslation) { return _requestingTranslation; } return _notTranslated; } } public IndividualTranslationViewModel(TranslatorViewModel translator, List translations) { _translator = translator; _translations = translations; } public void StartTranslations() { if (!_translator.IsEnabled || _hasStartedTranslation) { return; } _hasStartedTranslation = true; foreach (Translation translation in _translations) { translation.PerformTranslation(_translator.Endpoint); } } public void CheckCompleted() { if (_translator.IsEnabled && !_isTranslated && _translations.All((Translation x) => x.TranslatedText != null)) { _isTranslated = true; } } public void CopyToClipboard() { if (_isTranslated) { ClipboardHelper.CopyToClipboard(_translations.Select((Translation x) => x.TranslatedText), 32767); } } public bool CanCopyToClipboard() { return _isTranslated; } } internal class IndividualTranslatorTranslationViewModel { public TranslatorViewModel Translator { get; private set; } public IndividualTranslationViewModel Translation { get; private set; } public IndividualTranslatorTranslationViewModel(TranslatorViewModel translator, IndividualTranslationViewModel translation) { Translator = translator; Translation = translation; } public void CopyToClipboard() { Translation.CopyToClipboard(); } public bool CanCopyToClipboard() { return Translation.CanCopyToClipboard(); } } internal class LabelViewModel { public string Title { get; set; } public Func GetValue { get; set; } public LabelViewModel(string title, Func getValue) { Title = title; GetValue = getValue; } } internal class ScrollPositioned { public Vector2 ScrollPosition { get; set; } } internal class ScrollPositioned : ScrollPositioned { public TViewModel ViewModel { get; private set; } public ScrollPositioned(TViewModel viewModel) { ViewModel = viewModel; } } internal class ToggleViewModel { private GUIContent _enabled; private GUIContent _disabled; public GUIContent Text { get { if (IsToggled()) { return _enabled; } return _disabled; } } public bool Enabled { get; set; } public Action OnToggled { get; set; } public Func IsToggled { get; set; } public ToggleViewModel(string text, string enabledTooltip, string disabledTooltip, Action onToggled, Func isToggled, bool enabled = true) { _enabled = GUIUtil.CreateContent(text, enabledTooltip); _disabled = GUIUtil.CreateContent(text, disabledTooltip); OnToggled = onToggled; IsToggled = isToggled; Enabled = enabled; } } internal class Translation { public string OriginalText { get; set; } public string TranslatedText { get; set; } public Translation(string originalText, string translatedText) { OriginalText = originalText; TranslatedText = translatedText; } public void PerformTranslation(TranslationEndpointManager endpoint) { AutoTranslator.Internal.TranslateAsync(endpoint, OriginalText, Response_Completed); } private void Response_Completed(TranslationResult result) { if (result.Succeeded) { TranslatedText = result.TranslatedText; } else { TranslatedText = result.ErrorMessage; } } } internal class TranslationAggregatorOptionsWindow { private static bool _isScrollViewSupported = true; private const int WindowId = 45733721; private const float WindowWidth = 320f; private Rect _windowRect = new Rect(20f, 20f, 320f, 400f); private bool _isMouseDownOnWindow; private TranslationAggregatorViewModel _viewModel; private List _toggles; private Vector2 _scrollPosition; public bool IsShown { get { return _viewModel.IsShowingOptions; } set { _viewModel.IsShowingOptions = value; } } public TranslationAggregatorOptionsWindow(TranslationAggregatorViewModel viewModel) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) _viewModel = viewModel; _toggles = _viewModel.AllTranslators.Select((TranslatorViewModel x) => new ToggleViewModel(" " + x.Endpoint.Endpoint.FriendlyName, null, null, delegate { x.IsEnabled = !x.IsEnabled; }, () => x.IsEnabled, x.Endpoint.Error == null)).ToList(); } public void OnGUI() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) GUI.Box(_windowRect, GUIUtil.none, GUIUtil.GetWindowBackgroundStyle()); _windowRect = GUI.Window(45733721, _windowRect, new WindowFunction(CreateWindowUI), "---- Translation Aggregator Options ----"); if (GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe) { Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); _isMouseDownOnWindow = ((Rect)(ref _windowRect)).Contains(val); } if (_isMouseDownOnWindow && GUIUtil.IsAnyMouseButtonOrScrollWheelSafe) { GUI.FocusWindow(45733721); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); if (((Rect)(ref _windowRect)).Contains(val2)) { UnityInput.Current.ResetInputAxes(); } } } private void CreateWindowUI(int id) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) try { AutoTranslationPlugin.Current.DisableAutoTranslator(); if (GUI.Button(GUIUtil.R(298f, 2f, 20f, 16f), "X")) { IsShown = false; } GUILayout.Label("Available Translators", ArrayHelper.Null()); if (_isScrollViewSupported) { bool flag = false; try { _scrollPosition = GUILayout.BeginScrollView(_scrollPosition, GUI.skin.box, ArrayHelper.Null()); flag = true; foreach (ToggleViewModel toggle in _toggles) { bool enabled = GUI.enabled; GUI.enabled = toggle.Enabled; bool num = toggle.IsToggled(); bool flag2 = GUILayout.Toggle(num, toggle.Text, ArrayHelper.Null()); if (num != flag2) { toggle.OnToggled(); } GUI.enabled = enabled; } } catch (Exception ex) { if (!(ex is NotSupportedException)) { throw; } XuaLogger.AutoTranslator.Warn(ex, "An error occurred while calling GUILayout.BeginScrollView. Fallback mode will be used."); _isScrollViewSupported = false; } finally { if (flag) { GUILayout.EndScrollView(); } } } if (!_isScrollViewSupported) { GUILayout.BeginVertical(GUI.skin.box, ArrayHelper.Null()); foreach (ToggleViewModel toggle2 in _toggles) { bool enabled2 = GUI.enabled; GUI.enabled = toggle2.Enabled; bool num2 = toggle2.IsToggled(); bool flag3 = GUILayout.Toggle(num2, toggle2.Text, ArrayHelper.Null()); if (num2 != flag3) { toggle2.OnToggled(); } GUI.enabled = enabled2; } GUILayout.EndVertical(); } GUILayout.BeginHorizontal(ArrayHelper.Null()); GUILayout.Label("Height", ArrayHelper.Null()); _viewModel.Height = Mathf.Round(GUILayout.HorizontalSlider(_viewModel.Height, 50f, 300f, ArrayHelper.Null())); GUILayout.EndHorizontal(); GUILayout.BeginHorizontal(ArrayHelper.Null()); GUILayout.Label("Width", ArrayHelper.Null()); _viewModel.Width = Mathf.Round(GUILayout.HorizontalSlider(_viewModel.Width, 200f, 1000f, ArrayHelper.Null())); GUILayout.EndHorizontal(); GUI.DragWindow(); } finally { AutoTranslationPlugin.Current.EnableAutoTranslator(); } } } internal class TranslationAggregatorViewModel { private DebounceFunction _saveHeightAndWidth; private LinkedList _translations; private LinkedListNode _current; private List _translationsToAggregate = new List(); private HashSet _textsToAggregate = new HashSet(); private float _lastUpdate; private float _height; private float _width; public bool IsShown { get; set; } public bool IsShowingOptions { get; set; } public float Height { get { return _height; } set { if (_height != value) { _height = value; _saveHeightAndWidth.Execute(); } } } public float Width { get { return _width; } set { if (_width != value) { _width = value; _saveHeightAndWidth.Execute(); } } } public List AvailableTranslators { get; } public List AllTranslators { get; } public TranslationManager Manager { get; set; } public AggregatedTranslationViewModel Current => _current?.Value; public TranslationAggregatorViewModel(TranslationManager translationManager) { _translations = new LinkedList(); _saveHeightAndWidth = new DebounceFunction(1f, SaveHeightAndWidth); Manager = translationManager; Height = Settings.Height; Width = Settings.Width; AllTranslators = translationManager.AllEndpoints.Select((TranslationEndpointManager x) => new TranslatorViewModel(x)).ToList(); AvailableTranslators = AllTranslators.Where((TranslatorViewModel x) => x.Endpoint.Error == null).ToList(); } private void SaveHeightAndWidth() { Settings.SetTranslationAggregatorBounds(Width, Height); } public void OnNewTranslationAdded(string originalText, string defaultTranslation) { if (!_textsToAggregate.Contains(originalText)) { Translation item = new Translation(originalText, defaultTranslation); _textsToAggregate.Add(originalText); _translationsToAggregate.Add(item); _lastUpdate = Time.realtimeSinceStartup; if (_translationsToAggregate.Count >= 10) { CreateNewAggregatedTranslation(); } } } private void CreateNewAggregatedTranslation() { try { List translations = _translationsToAggregate.ToList(); AggregatedTranslationViewModel value = new AggregatedTranslationViewModel(this, translations); LinkedListNode last = _translations.Last; _translations.AddLast(value); if (_current == null) { _current = _translations.Last; } else if (_current == last) { _current = _translations.Last; } if (_translations.Count >= 100) { LinkedListNode first = _translations.First; _translations.RemoveFirst(); if (_current == first) { _current = _translations.First; } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error while copying text to clipboard."); } finally { _textsToAggregate.Clear(); _translationsToAggregate.Clear(); } } public void Update() { if (_translationsToAggregate.Count > 0 && Time.realtimeSinceStartup - _lastUpdate > Settings.ClipboardDebounceTime) { CreateNewAggregatedTranslation(); } if (_current != null) { _current.Value.Update(); } } public bool HasPrevious() { return _current?.Previous != null; } public void MovePrevious() { _current = _current.Previous; } public bool HasNext() { return _current?.Next != null; } public void MoveNext() { _current = _current.Next; } public void MoveLatest() { _current = _translations.Last; } } internal class TranslationAggregatorWindow { private static string[] Empty = new string[0]; private const int WindowId = 2387602; private Rect _windowRect; private bool _isMouseDownOnWindow; private TranslationAggregatorViewModel _viewModel; private ScrollPositioned _originalText; private ScrollPositioned _defaultTranslation; private ScrollPositioned[] _translationViews; private static bool _isScrollViewSupported = true; public bool IsShown { get { return _viewModel.IsShown; } set { _viewModel.IsShown = value; } } private float WindowHeight => (float)(_viewModel.AvailableTranslators.Count((TranslatorViewModel x) => x.IsEnabled) + 2) * _viewModel.Height + 30f + 21f + 10f; public TranslationAggregatorWindow(TranslationAggregatorViewModel viewModel) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) _viewModel = viewModel; _windowRect = new Rect(20f, 20f, _viewModel.Width, WindowHeight); _originalText = new ScrollPositioned(); _defaultTranslation = new ScrollPositioned(); _translationViews = viewModel.AvailableTranslators.Select((TranslatorViewModel x) => new ScrollPositioned(x)).ToArray(); } public void OnGUI() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Expected O, but got Unknown //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) ((Rect)(ref _windowRect)).height = WindowHeight; ((Rect)(ref _windowRect)).width = _viewModel.Width; _windowRect = GUI.Window(2387602, _windowRect, new WindowFunction(CreateWindowUI), "---- Translation Aggregator ----"); if (GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe) { Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); _isMouseDownOnWindow = ((Rect)(ref _windowRect)).Contains(val); } if (_isMouseDownOnWindow && GUIUtil.IsAnyMouseButtonOrScrollWheelSafe) { GUI.FocusWindow(2387602); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); if (((Rect)(ref _windowRect)).Contains(val2)) { UnityInput.Current.ResetInputAxes(); } } } public void Update() { _viewModel.Update(); } public void OnNewTranslationAdded(string originalText, string defaultTranslation) { _viewModel.OnNewTranslationAdded(originalText, defaultTranslation); } private void CreateWindowUI(int id) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_03d7: Unknown result type (might be due to invalid IL or missing references) //IL_034a: Unknown result type (might be due to invalid IL or missing references) //IL_0413: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0493: Unknown result type (might be due to invalid IL or missing references) //IL_0197: Unknown result type (might be due to invalid IL or missing references) try { AutoTranslationPlugin.Current.DisableAutoTranslator(); float num = 20f; if (GUI.Button(GUIUtil.R(_viewModel.Width - 22f, 2f, 20f, 16f), "X")) { IsShown = false; } AggregatedTranslationViewModel current = _viewModel.Current; if (current != null) { if (GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy")) { current.CopyOriginalTextToClipboard(); } DrawTextArea(num, _originalText, "Original Text", current.OriginalTexts); num += _viewModel.Height; if (GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy")) { current.CopyDefaultTranslationToClipboard(); } DrawTextArea(num, _defaultTranslation, "Default Translation", current.DefaultTranslations); num += _viewModel.Height; for (int i = 0; i < current.AggregatedTranslations.Count; i++) { IndividualTranslatorTranslationViewModel individualTranslatorTranslationViewModel = current.AggregatedTranslations[i]; if (individualTranslatorTranslationViewModel.Translator.IsEnabled) { ScrollPositioned positioned = _translationViews[i]; GUI.enabled = individualTranslatorTranslationViewModel.CanCopyToClipboard(); if (GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy")) { individualTranslatorTranslationViewModel.CopyToClipboard(); } GUI.enabled = true; DrawTextArea(num, positioned, individualTranslatorTranslationViewModel.Translator.Endpoint.Endpoint.FriendlyName, individualTranslatorTranslationViewModel.Translation.Translations); num += _viewModel.Height; } } } else { GUI.enabled = false; GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy"); GUI.enabled = true; DrawTextArea(num, _originalText, "Original Text", Empty); num += _viewModel.Height; GUI.enabled = false; GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy"); GUI.enabled = true; DrawTextArea(num, _defaultTranslation, "Default Translation", Empty); num += _viewModel.Height; for (int j = 0; j < _viewModel.AvailableTranslators.Count; j++) { TranslatorViewModel translatorViewModel = _viewModel.AvailableTranslators[j]; if (translatorViewModel.IsEnabled) { ScrollPositioned positioned2 = _translationViews[j]; GUI.enabled = false; GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 50f, num + 5f + 1f, 50f, 21f), "Copy"); GUI.enabled = true; DrawTextArea(num, positioned2, translatorViewModel.Endpoint.Endpoint.FriendlyName, Empty); num += _viewModel.Height; } } } num += 15f; bool enabled = GUI.enabled; GUI.enabled = _viewModel.HasPrevious(); if (GUI.Button(GUIUtil.R(5f, num, 75f, 21f), "Previous")) { _viewModel.MovePrevious(); } GUI.enabled = _viewModel.HasNext(); if (GUI.Button(GUIUtil.R(85f, num, 75f, 21f), "Next")) { _viewModel.MoveNext(); } GUI.enabled = _viewModel.HasNext(); if (GUI.Button(GUIUtil.R(165f, num, 75f, 21f), "Last")) { _viewModel.MoveLatest(); } GUI.enabled = true; if (GUI.Button(GUIUtil.R(_viewModel.Width - 5f - 75f, num, 75f, 21f), "Options")) { _viewModel.IsShowingOptions = true; } GUI.enabled = enabled; GUI.DragWindow(); } finally { AutoTranslationPlugin.Current.EnableAutoTranslator(); } } private void DrawTextArea(float posy, ScrollPositioned positioned, string title, IEnumerable texts) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) GUI.Label(GUIUtil.R(10f, posy + 5f, _viewModel.Width - 10f, 21f), title); posy += 26f; float width = _viewModel.Width - 10f; float height = _viewModel.Height - 21f; if (!_isScrollViewSupported) { GUILayout.BeginArea(GUIUtil.R(5f, posy, width, height)); } else { GUILayout.BeginArea(GUIUtil.R(5f, posy, width, height), GUI.skin.box); } if (_isScrollViewSupported) { bool flag = false; try { positioned.ScrollPosition = GUILayout.BeginScrollView(positioned.ScrollPosition, ArrayHelper.Null()); flag = true; foreach (string text in texts) { GUILayout.Label(text, GUIUtil.LabelTranslation, ArrayHelper.Null()); } } catch (Exception ex) { if (!(ex is NotSupportedException)) { throw; } XuaLogger.AutoTranslator.Warn(ex, "An error occurred while calling GUILayout.BeginScrollView. Fallback mode will be used."); _isScrollViewSupported = false; } finally { if (flag) { GUILayout.EndScrollView(); } } } if (!_isScrollViewSupported) { GUILayout.BeginVertical(GUI.skin.box, ArrayHelper.Null()); foreach (string text2 in texts) { GUILayout.Label(text2, GUIUtil.LabelTranslation, ArrayHelper.Null()); } GUILayout.EndVertical(); } GUILayout.EndArea(); } } internal class TranslatorViewModel { private bool _isEnabled; public TranslationEndpointManager Endpoint { get; set; } public bool IsEnabled { get { return _isEnabled; } set { if (_isEnabled != value) { _isEnabled = value; if (_isEnabled) { Settings.AddTranslator(Endpoint.Endpoint.Id); } else { Settings.RemoveTranslator(Endpoint.Endpoint.Id); } } } } public TranslatorViewModel(TranslationEndpointManager endpoint) { Endpoint = endpoint; IsEnabled = Settings.EnabledTranslators.Contains(endpoint.Endpoint.Id); } } internal class XuaViewModel { public bool IsShown { get; set; } public List Toggles { get; } public DropdownViewModel TranslatorDropdown { get; } public DropdownViewModel FallbackDropdown { get; } public List CommandButtons { get; } public List Labels { get; } public XuaViewModel(List toggles, DropdownViewModel translatorDropdown, DropdownViewModel fallbackDropdown, List commandButtons, List labels) { Toggles = toggles; TranslatorDropdown = translatorDropdown; FallbackDropdown = fallbackDropdown; CommandButtons = commandButtons; Labels = labels; } } internal class XuaWindow { private const int WindowId = 5464332; private const float WindowHeight = 596f; private const float WindowWidth = 320f; private Rect _windowRect = new Rect(20f, 20f, 320f, 596f); private DropdownGUI _endpointDropdown; private DropdownGUI _fallbackDropdown; private XuaViewModel _viewModel; private bool _isMouseDownOnWindow; public bool IsShown { get { return _viewModel.IsShown; } set { _viewModel.IsShown = value; } } public XuaWindow(XuaViewModel viewModel) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) _viewModel = viewModel; } public void OnGUI() { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) GUI.Box(_windowRect, GUIUtil.none, GUIUtil.GetWindowBackgroundStyle()); _windowRect = GUI.Window(5464332, _windowRect, new WindowFunction(CreateWindowUI), "---- XUnity.AutoTranslator UI ----"); if (GUIUtil.IsAnyMouseButtonOrScrollWheelDownSafe) { Vector2 val = default(Vector2); ((Vector2)(ref val))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); _isMouseDownOnWindow = ((Rect)(ref _windowRect)).Contains(val); } if (_isMouseDownOnWindow && GUIUtil.IsAnyMouseButtonOrScrollWheelSafe) { GUI.FocusWindow(5464332); Vector2 val2 = default(Vector2); ((Vector2)(ref val2))..ctor(UnityInput.Current.mousePosition.x, (float)Screen.height - UnityInput.Current.mousePosition.y); if (((Rect)(ref _windowRect)).Contains(val2)) { UnityInput.Current.ResetInputAxes(); } } } private void CreateWindowUI(int id) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_027d: Unknown result type (might be due to invalid IL or missing references) //IL_02a9: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_0332: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0391: Unknown result type (might be due to invalid IL or missing references) //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_01f4: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) try { AutoTranslationPlugin.Current.DisableAutoTranslator(); float num = 10f; float num2 = 20f; if (GUI.Button(GUIUtil.R(298f, 2f, 20f, 16f), "X")) { IsShown = false; } List toggles = _viewModel.Toggles; float height = 21f * (float)toggles.Count + 5f * (float)toggles.Count - 10f; GUI.Box(GUIUtil.R(5f, num2, 310f, height), ""); foreach (ToggleViewModel item in toggles) { bool flag = item.IsToggled(); bool flag2 = GUI.Toggle(GUIUtil.R(10f, num2 + 3f, 300f, 18f), flag, item.Text); if (flag != flag2) { item.OnToggled(); } num2 += 21f; } num2 += 10f; List commandButtons = _viewModel.CommandButtons; int num3 = commandButtons.Count / 3; if (commandButtons.Count % 3 != 0) { num3++; } height = 21f + 21f * (float)num3 + 10f * (float)(num3 + 1) - 5f; GUI.Box(GUIUtil.R(5f, num2, 310f, height), ""); GUI.Label(GUIUtil.R(10f, num2, 300f, 21f), "---- Command Panel ----", GUIUtil.LabelCenter); num2 += 31f; for (int i = 0; i < num3; i++) { for (int j = 0; j < 3; j++) { int num4 = i * 3 + j; if (num4 >= commandButtons.Count) { break; } ButtonViewModel buttonViewModel = commandButtons[num4]; GUI.enabled = buttonViewModel.CanClick?.Invoke() ?? true; if (GUI.Button(GUIUtil.R(num, num2, 93.333336f, 21f), buttonViewModel.Text)) { buttonViewModel.OnClicked?.Invoke(); } GUI.enabled = true; num += 103.333336f; } num2 += 31f; } height = 83f; GUI.Box(GUIUtil.R(5f, num2, 310f, height), ""); GUI.Label(GUIUtil.R(10f, num2, 300f, 21f), "---- Select a Translator ----", GUIUtil.LabelCenter); num2 += 31f; GUI.Label(GUIUtil.R(10f, num2, 70f, 21f), "Translator: "); float y = num2; num2 += 26f; GUI.Label(GUIUtil.R(10f, num2, 60f, 21f), "Fallback: "); float y2 = num2; num2 += 31f; List labels = _viewModel.Labels; height = 21f + 21f * (float)labels.Count + 10f * (float)(labels.Count + 1) - 5f; GUI.Box(GUIUtil.R(5f, num2, 310f, height), ""); GUI.Label(GUIUtil.R(10f, num2, 300f, 21f), "---- Status ----", GUIUtil.LabelCenter); num2 += 31f; foreach (LabelViewModel item2 in labels) { GUI.Label(GUIUtil.R(10f, num2, 300f, 21f), item2.Title); GUI.Label(GUIUtil.R(80f, num2, 230f, 21f), item2.GetValue(), GUIUtil.LabelRight); num2 += 31f; } bool flag3 = (_endpointDropdown ?? (_endpointDropdown = new DropdownGUI(80f, y, 230f, _viewModel.TranslatorDropdown))).OnGUI(enabled: true); (_fallbackDropdown ?? (_fallbackDropdown = new DropdownGUI(80f, y2, 230f, _viewModel.FallbackDropdown))).OnGUI(!flag3); GUI.Label(GUIUtil.R(10f, num2, 300f, 105f), GUI.tooltip, GUIUtil.LabelRich); GUI.DragWindow(); } finally { AutoTranslationPlugin.Current.EnableAutoTranslator(); } } } } namespace XUnity.AutoTranslator.Plugin.Core.UIResize { internal class AutoResize : IFontAutoResizeCommand { private bool _shouldAutoResize; private double? _minSize; private double? _maxSize; public AutoResize(string[] args) { if (args.Length < 1) { throw new ArgumentException("ChangeFontSize requires one, two or three argument."); } _shouldAutoResize = bool.Parse(args[0]); if (args.Length >= 2) { _minSize = ParseMinMaxSize(args[1]); } if (args.Length >= 3) { _maxSize = ParseMinMaxSize(args[2]); } } private static double? ParseMinMaxSize(string arg) { if (string.Equals(arg, "keep", StringComparison.OrdinalIgnoreCase)) { return null; } if (string.Equals(arg, "none", StringComparison.OrdinalIgnoreCase)) { return double.NaN; } return double.Parse(arg, CultureInfo.InvariantCulture); } public double? GetMinSize() { return _minSize; } public double? GetMaxSize() { return _maxSize; } public bool ShouldAutoResize() { return _shouldAutoResize; } } internal class ChangeFontSize : IFontResizeCommand { private int? _size; public ChangeFontSize(string[] args) { if (args.Length != 1) { throw new ArgumentException("ChangeFontSize requires one argument."); } _size = int.Parse(args[0], CultureInfo.InvariantCulture); } public int? GetSize(int currentSize) { return _size; } } internal class ChangeFontSizeByPercentage : IFontResizeCommand { private double _perc; public ChangeFontSizeByPercentage(string[] args) { if (args.Length != 1) { throw new ArgumentException("ChangeFontSizeByPercentage requires one argument."); } _perc = double.Parse(args[0], CultureInfo.InvariantCulture); } public int? GetSize(int currentSize) { return (int)((double)currentSize * _perc); } } internal interface IFontAutoResizeCommand { bool ShouldAutoResize(); double? GetMinSize(); double? GetMaxSize(); } internal interface IFontResizeCommand { int? GetSize(int currentSize); } internal class IgnoreFontSize : IFontResizeCommand { public IgnoreFontSize(string[] args) { if (args.Length != 0) { throw new ArgumentException("IgnoreFontSize requires zero argument."); } } public int? GetSize(int currentSize) { return null; } } internal interface ITMP_Alignment { int? GetMode(); } internal interface ITMP_OverflowMode { int? GetMode(); } internal interface IUGUI_HorizontalOverflow { int? GetMode(); } internal interface IUGUI_LineSpacingCommand { float? GetLineSpacing(float currentLineSpacing); } internal interface IUGUI_VerticalOverflow { int? GetMode(); } internal class TMP_Alignment : ITMP_Alignment { private int? _mode; public TMP_Alignment(string[] args) { if (args.Length != 1) { throw new ArgumentException("TMP_Alignment requires one argument."); } _mode = (int)EnumHelper.GetValues(UnityTypes.TextAlignmentOptions, args[0]); } public int? GetMode() { return _mode; } } internal class TMP_Overflow : ITMP_OverflowMode { private int? _mode; public TMP_Overflow(string[] args) { if (args.Length != 1) { throw new ArgumentException("TMP_Overflow requires one argument."); } _mode = (int)EnumHelper.GetValues(UnityTypes.TextOverflowModes, args[0]); } public int? GetMode() { return _mode; } } internal class UGUI_ChangeLineSpacing : IUGUI_LineSpacingCommand { private float? _size; public UGUI_ChangeLineSpacing(string[] args) { if (args.Length != 1) { throw new ArgumentException("UGUI_ChangeLineSpacing requires one argument."); } _size = float.Parse(args[0], CultureInfo.InvariantCulture); } public float? GetLineSpacing(float currentSize) { return _size; } } internal class UGUI_ChangeLineSpacingByPercentage : IUGUI_LineSpacingCommand { private float _perc; public UGUI_ChangeLineSpacingByPercentage(string[] args) { if (args.Length != 1) { throw new ArgumentException("UGUI_ChangeLineSpacingByPercentage requires one argument."); } _perc = float.Parse(args[0], CultureInfo.InvariantCulture); } public float? GetLineSpacing(float currentSize) { return currentSize * _perc; } } internal class UGUI_HorizontalOverflow : IUGUI_HorizontalOverflow { private int? _mode; public UGUI_HorizontalOverflow(string[] args) { if (args.Length != 1) { throw new ArgumentException("UGUI_HorizontalOverflow requires one argument."); } _mode = (int)EnumHelper.GetValues(UnityTypes.HorizontalWrapMode, args[0]); } public int? GetMode() { return _mode; } } internal class UGUI_VerticalOverflow : IUGUI_VerticalOverflow { private int? _mode; public UGUI_VerticalOverflow(string[] args) { if (args.Length != 1) { throw new ArgumentException("UGUI_VerticalOverflow requires one argument."); } _mode = (int)EnumHelper.GetValues(UnityTypes.VerticalWrapMode, args[0]); } public int? GetMode() { return _mode; } } internal class UIResizeAttachment { private static readonly char[] CommandSplitters; private static readonly char[] PathSplitters; private static readonly char[] ArgSplitters; private static Regex CommandRegex; private static Dictionary CommandTypes; public Dictionary Descendants { get; } public Dictionary ScopedResults { get; } public UIResizeResult Result { get; private set; } static UIResizeAttachment() { CommandSplitters = new char[1] { ';' }; PathSplitters = new char[1] { '/' }; ArgSplitters = new char[2] { ',', ' ' }; CommandRegex = new Regex("^\\s*(.+)\\s*\\(([\\s\\S]*)\\)\\s*$", AutoTranslationPlugin.RegexCompiledSupportedFlag); CommandTypes = new Dictionary(StringComparer.OrdinalIgnoreCase); try { Type[] array = new Type[10] { typeof(ChangeFontSize), typeof(ChangeFontSizeByPercentage), typeof(IgnoreFontSize), typeof(AutoResize), typeof(UGUI_ChangeLineSpacing), typeof(UGUI_ChangeLineSpacingByPercentage), typeof(UGUI_HorizontalOverflow), typeof(UGUI_VerticalOverflow), typeof(TMP_Overflow), typeof(TMP_Alignment) }; foreach (Type type in array) { CommandTypes[type.Name] = type; } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading ui resize commands."); } } public UIResizeAttachment() { Descendants = new Dictionary(); Result = new UIResizeResult(); ScopedResults = new Dictionary(); } public bool AddResizeCommand(string path, string commands, int scope) { string[] segments = path.Split(PathSplitters, StringSplitOptions.RemoveEmptyEntries); UIResizeAttachment orCreateAttachment = GetOrCreateAttachment(segments); string[] array = commands.Split(CommandSplitters, StringSplitOptions.RemoveEmptyEntries); bool result = false; string[] array2 = array; foreach (string text in array2) { Match match = CommandRegex.Match(text); if (!match.Success) { XuaLogger.AutoTranslator.Warn("Could not understand command: " + text); continue; } try { string value = match.Groups[1].Value; string[] array3 = match.Groups[2].Value.Split(ArgSplitters, StringSplitOptions.RemoveEmptyEntries); UIResizeResult uIResizeResult = ((scope == -1) ? orCreateAttachment.Result : orCreateAttachment.GetOrCreateResultFor(scope)); if (CommandTypes.TryGetValue(value, out var value2)) { object? obj = Activator.CreateInstance(value2, new object[1] { array3 }); if (obj is IFontResizeCommand resizeCommand) { uIResizeResult.ResizeCommand = resizeCommand; uIResizeResult.IsResizeCommandScoped = scope != -1; } if (obj is IFontAutoResizeCommand autoResizeCommand) { uIResizeResult.AutoResizeCommand = autoResizeCommand; uIResizeResult.IsAutoResizeCommandScoped = scope != -1; } if (obj is IUGUI_LineSpacingCommand lineSpacingCommand) { uIResizeResult.LineSpacingCommand = lineSpacingCommand; uIResizeResult.IsLineSpacingCommandScoped = scope != -1; } if (obj is IUGUI_HorizontalOverflow horizontalOverflowCommand) { uIResizeResult.HorizontalOverflowCommand = horizontalOverflowCommand; uIResizeResult.IsHorizontalOverflowCommandScoped = scope != -1; } if (obj is IUGUI_VerticalOverflow verticalOverflowCommand) { uIResizeResult.VerticalOverflowCommand = verticalOverflowCommand; uIResizeResult.IsVerticalOverflowCommandScoped = scope != -1; } if (obj is ITMP_OverflowMode overflowCommand) { uIResizeResult.OverflowCommand = overflowCommand; uIResizeResult.IsOverflowCommandScoped = scope != -1; } if (obj is ITMP_Alignment alignmentCommand) { uIResizeResult.AlignmentCommand = alignmentCommand; uIResizeResult.IsAlignmentCommandScoped = scope != -1; } result = true; continue; } throw new ArgumentException("Unknown command: " + value); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while creating UI resize command."); } } return result; } private UIResizeResult GetOrCreateResultFor(int scope) { if (!ScopedResults.TryGetValue(scope, out var value)) { value = new UIResizeResult(); ScopedResults[scope] = value; } return value; } private UIResizeAttachment GetOrCreateAttachment(string[] segments) { UIResizeAttachment uIResizeAttachment = this; int num = segments.Length; for (int i = 0; i < num; i++) { string key = segments[i]; if (!uIResizeAttachment.Descendants.TryGetValue(key, out var value)) { value = new UIResizeAttachment(); uIResizeAttachment.Descendants[key] = value; } uIResizeAttachment = value; } return uIResizeAttachment; } public void Trim() { if (Result != null && Result.IsEmpty()) { Result = null; } foreach (UIResizeAttachment value in Descendants.Values) { value.Trim(); } } public bool TryGetUIResize(string[] segments, int startIndex, int scope, out UIResizeResult result) { UIResizeAttachment uIResizeAttachment = this; result = null; int num = segments.Length; for (int i = startIndex; i < num; i++) { string key = segments[i]; if (uIResizeAttachment.Descendants.TryGetValue(key, out var value)) { if (result == null) { result = value.Result?.Copy(); } else { result.MergeInto(value.Result); } if (scope != -1) { UIResizeResult value3; if (result == null) { if (value.ScopedResults.TryGetValue(scope, out var value2)) { result = value2.Copy(); } } else if (value.ScopedResults.TryGetValue(scope, out value3)) { result.MergeInto(value3); } } uIResizeAttachment = value; continue; } return result != null; } return result != null; } } internal class UIResizeCache { private UIResizeAttachment _root = new UIResizeAttachment(); public bool HasAnyResizeCommands { get; private set; } private static IEnumerable GetTranslationFiles() { return from x in Directory.GetFiles(Settings.TranslationsPath, "*.*", SearchOption.AllDirectories) where x.EndsWith("resizer.txt", StringComparison.OrdinalIgnoreCase) || x.EndsWith(".zip", StringComparison.OrdinalIgnoreCase) select x; } internal void LoadResizeCommandsInFiles() { try { Directory.CreateDirectory(Settings.TranslationsPath); Directory.CreateDirectory(Path.GetDirectoryName(Settings.AutoTranslationsFilePath)); _root = new UIResizeAttachment(); foreach (string item in GetTranslationFiles().Reverse()) { LoadResizeCommandsInFile(item); } _root.Trim(); XuaLogger.AutoTranslator.Debug("Loaded resize command text files."); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while resize commands."); } } private void LoadResizeCommandsInStream(Stream stream, string fullFileName) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Loading resize commands: " + fullFileName + "."); } StreamReader streamReader = new StreamReader(stream, Encoding.UTF8); TranslationFileLoadingContext translationFileLoadingContext = new TranslationFileLoadingContext(); string[] array = streamReader.ReadToEnd().Split(new char[2] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { TranslationFileDirective translationFileDirective = TranslationFileDirective.Create(text); if (translationFileDirective != null) { translationFileLoadingContext.Apply(translationFileDirective); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Directive in file: " + fullFileName + ": " + translationFileDirective.ToString()); } } else { if (!translationFileLoadingContext.IsApplicable()) { continue; } try { string[] array2 = TextHelper.ReadTranslationLineAndDecode(text); if (array2 == null) { continue; } string text2 = array2[0]; string value = array2[1]; if (string.IsNullOrEmpty(text2) || string.IsNullOrEmpty(value)) { continue; } HashSet levels = translationFileLoadingContext.GetLevels(); if (levels.Count == 0) { AddTranslation(text2, value, -1); continue; } foreach (int item in levels) { AddTranslation(text2, value, item); } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while reading UI resize directive: '" + text + "'."); } } } } private void LoadResizeCommandsInFile(string fullFileName) { if (!File.Exists(fullFileName)) { return; } using FileStream fileStream = File.OpenRead(fullFileName); if (fullFileName.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { using (ZipInputStream zipInputStream = new ZipInputStream(fileStream)) { while (true) { ZipEntry nextEntry = zipInputStream.GetNextEntry(); if (nextEntry == null) { break; } if (nextEntry.IsFile && nextEntry.Name.EndsWith("resizer.txt", StringComparison.OrdinalIgnoreCase)) { char directorySeparatorChar = Path.DirectorySeparatorChar; LoadResizeCommandsInStream(zipInputStream, fullFileName + directorySeparatorChar + nextEntry.Name); } } return; } } LoadResizeCommandsInStream(fileStream, fullFileName); } private void AddTranslation(string key, string value, int scope) { if (key != null && value != null) { bool flag = _root.AddResizeCommand(key, value, scope); HasAnyResizeCommands = flag || HasAnyResizeCommands; } } public bool TryGetUIResize(string[] paths, int scope, out UIResizeResult result) { return _root.TryGetUIResize(paths, 0, scope, out result); } } internal class UIResizeResult { public IFontResizeCommand ResizeCommand { get; set; } public bool IsResizeCommandScoped { get; set; } public IFontAutoResizeCommand AutoResizeCommand { get; set; } public bool IsAutoResizeCommandScoped { get; set; } public IUGUI_LineSpacingCommand LineSpacingCommand { get; set; } public bool IsLineSpacingCommandScoped { get; set; } public IUGUI_HorizontalOverflow HorizontalOverflowCommand { get; set; } public bool IsHorizontalOverflowCommandScoped { get; set; } public IUGUI_VerticalOverflow VerticalOverflowCommand { get; set; } public bool IsVerticalOverflowCommandScoped { get; set; } public ITMP_OverflowMode OverflowCommand { get; set; } public bool IsOverflowCommandScoped { get; set; } public ITMP_Alignment AlignmentCommand { get; set; } public bool IsAlignmentCommandScoped { get; set; } public bool IsEmpty() { if (ResizeCommand == null && AutoResizeCommand == null && LineSpacingCommand == null && HorizontalOverflowCommand == null && VerticalOverflowCommand == null && OverflowCommand == null) { return AlignmentCommand == null; } return false; } public UIResizeResult Copy() { return (UIResizeResult)MemberwiseClone(); } public void MergeInto(UIResizeResult otherResult) { if (otherResult != null) { if (otherResult.ResizeCommand != null && (otherResult.IsResizeCommandScoped || (!otherResult.IsResizeCommandScoped && !IsResizeCommandScoped))) { ResizeCommand = otherResult.ResizeCommand; IsResizeCommandScoped = otherResult.IsResizeCommandScoped; } if (otherResult.AutoResizeCommand != null && (otherResult.IsAutoResizeCommandScoped || (!otherResult.IsAutoResizeCommandScoped && !IsAutoResizeCommandScoped))) { AutoResizeCommand = otherResult.AutoResizeCommand; IsAutoResizeCommandScoped = otherResult.IsAutoResizeCommandScoped; } if (otherResult.LineSpacingCommand != null && (otherResult.IsLineSpacingCommandScoped || (!otherResult.IsLineSpacingCommandScoped && !IsLineSpacingCommandScoped))) { LineSpacingCommand = otherResult.LineSpacingCommand; IsLineSpacingCommandScoped = otherResult.IsLineSpacingCommandScoped; } if (otherResult.HorizontalOverflowCommand != null && (otherResult.IsHorizontalOverflowCommandScoped || (!otherResult.IsHorizontalOverflowCommandScoped && !IsHorizontalOverflowCommandScoped))) { HorizontalOverflowCommand = otherResult.HorizontalOverflowCommand; IsHorizontalOverflowCommandScoped = otherResult.IsHorizontalOverflowCommandScoped; } if (otherResult.VerticalOverflowCommand != null && (otherResult.IsVerticalOverflowCommandScoped || (!otherResult.IsVerticalOverflowCommandScoped && !IsVerticalOverflowCommandScoped))) { VerticalOverflowCommand = otherResult.VerticalOverflowCommand; IsVerticalOverflowCommandScoped = otherResult.IsVerticalOverflowCommandScoped; } if (otherResult.OverflowCommand != null && (otherResult.IsOverflowCommandScoped || (!otherResult.IsOverflowCommandScoped && !IsOverflowCommandScoped))) { OverflowCommand = otherResult.OverflowCommand; IsOverflowCommandScoped = otherResult.IsOverflowCommandScoped; } if (otherResult.AlignmentCommand != null && (otherResult.IsAlignmentCommandScoped || (!otherResult.IsAlignmentCommandScoped && !IsAlignmentCommandScoped))) { AlignmentCommand = otherResult.AlignmentCommand; IsAlignmentCommandScoped = otherResult.IsAlignmentCommandScoped; } } } } } namespace XUnity.AutoTranslator.Plugin.Core.Text { internal class DefaultTextComponentManipulator : ITextComponentManipulator { private class TypeAndMethod { private FastReflectionDelegate _setterInvoker; public Type Type { get; } public MethodBase SetterMethod { get; } public FastReflectionDelegate SetterInvoker => _setterInvoker ?? (_setterInvoker = CustomFastReflectionHelper.CreateFastDelegate(SetterMethod, true, true)); public TypeAndMethod(Type type, MethodBase method) { Type = type; SetterMethod = method; } } private static readonly string TextPropertyName = "text"; private readonly Type _type; private readonly CachedProperty _property; private static Dictionary _textSetters = new Dictionary(); public DefaultTextComponentManipulator(Type type) { _type = type; _property = ReflectionCache.CachedProperty(type, TextPropertyName); } public string GetText(object ui) { CachedProperty property = _property; return (string)((property != null) ? property.Get(ui) : null); } public void SetText(object ui, string text) { Type type = _type; if (UnityTypes.TextWindow != null) { TypeContainer textMeshPro = UnityTypes.TextMeshPro; if (textMeshPro != null && textMeshPro.ClrType.IsAssignableFrom(type)) { Object textWindow = Object.FindObjectOfType(UnityTypes.TextWindow.ClrType); if (textWindow != (Object)null) { BindingFlags flags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; object obj = ((object)textWindow).GetType().GetField("TextMesh", flags)?.GetValue(textWindow); if (obj != null && object.Equals(obj, ui)) { if (new StackTrace().GetFrames().Any((StackFrame x) => (object)x.GetMethod().DeclaringType == UnityTypes.TextWindow.ClrType)) { object previousCurText = ((object)textWindow).GetType().GetField("curText", flags).GetValue(textWindow); ((object)textWindow).GetType().GetField("curText", flags).SetValue(textWindow, text); Settings.SetCurText = delegate(object textWindowInner) { object value3 = ((object)textWindow).GetType().GetField("curText", flags).GetValue(textWindow); if (object.Equals(text, value3)) { textWindowInner.GetType().GetMethod("FinishTyping", flags).Invoke(textWindowInner, null); textWindowInner.GetType().GetField("curText", flags).SetValue(textWindowInner, previousCurText); object value4 = textWindowInner.GetType().GetField("TextMesh", flags).GetValue(textWindowInner); object value5 = textWindowInner.GetType().GetField("Keyword", flags).GetValue(textWindowInner); value5.GetType().GetMethod("UpdateTextMesh", flags).Invoke(value5, new object[2] { value4, true }); } Settings.SetCurText = null; }; } else { CachedProperty obj2 = ReflectionCache.CachedProperty(type, TextPropertyName); if (obj2 != null) { obj2.Set(ui, (object)text); } object value = ((object)textWindow).GetType().GetField("curText", flags).GetValue(textWindow); ((object)textWindow).GetType().GetField("curText", flags).SetValue(textWindow, text); ((object)textWindow).GetType().GetMethod("FinishTyping", flags).Invoke(textWindow, null); ((object)textWindow).GetType().GetField("curText", flags).SetValue(textWindow, value); object value2 = ((object)textWindow).GetType().GetField("Keyword", flags).GetValue(textWindow); value2.GetType().GetMethod("UpdateTextMesh", flags).Invoke(value2, new object[2] { obj, true }); } return; } } } } CachedProperty property = _property; if (property != null) { property.Set(ui, (object)text); if (Settings.IgnoreVirtualTextSetterCallingRules) { string text2 = (string)property.Get(ui); Type type2 = type; while (text != text2 && (object)type2 != null) { TypeAndMethod textPropertySetterInParent = GetTextPropertySetterInParent(type2); if (textPropertySetterInParent != null) { type2 = textPropertySetterInParent.Type; textPropertySetterInParent.SetterInvoker.Invoke(ui, new object[1] { text }); text2 = (string)property.Get(ui); } else { type2 = null; } } } } CachedProperty val = ReflectionCache.CachedProperty(type, "maxVisibleCharacters"); if (val != null && (object)val.PropertyType == typeof(int)) { int num = (int)val.Get(ui); if (0 < num && num < 99999) { val.Set(ui, (object)99999); } } if (TextExpansion_Methods.SetMessageType != null && TextExpansion_Methods.SkipTypeWriter != null && UnityTypes.TextExpansion.ClrType.IsAssignableFrom(type)) { TextExpansion_Methods.SetMessageType.Invoke(ui, (object)1); TextExpansion_Methods.SkipTypeWriter.Invoke(ui); } } private static TypeAndMethod GetTextPropertySetterInParent(Type type) { Type baseType = type.BaseType; while ((object)baseType != null) { if (_textSetters.TryGetValue(type, out var value)) { return value; } PropertyInfo property = baseType.GetProperty(TextPropertyName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); if ((object)property != null && property.CanWrite) { TypeAndMethod typeAndMethod = new TypeAndMethod(baseType, property.GetSetMethod()); _textSetters[baseType] = typeAndMethod; return typeAndMethod; } baseType = baseType.BaseType; } return null; } } internal class FairyGUITextComponentManipulator : ITextComponentManipulator { private readonly CachedField _html; private readonly CachedProperty _htmlText; private readonly CachedProperty _text; public FairyGUITextComponentManipulator() { _html = ReflectionCache.CachedField(UnityTypes.TextField.ClrType, "html") ?? ReflectionCache.CachedFieldByIndex(UnityTypes.TextField.ClrType, 3, typeof(bool), BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); _text = ReflectionCache.CachedProperty(UnityTypes.TextField.ClrType, "text"); _htmlText = ReflectionCache.CachedProperty(UnityTypes.TextField.ClrType, "htmlText"); } public string GetText(object ui) { if ((bool)_html.Get(ui)) { return (string)_htmlText.Get(ui); } return (string)_text.Get(ui); } public void SetText(object ui, string text) { if ((bool)_html.Get(ui)) { _htmlText.Set(ui, (object)text); } else { _text.Set(ui, (object)text); } } } internal interface ITextComponentManipulator { string GetText(object ui); void SetText(object ui, string text); } internal class TextArea2DComponentManipulator : ITextComponentManipulator { private readonly Action set_status; private readonly Action set_textData; private readonly Action set_nameText; private readonly Action set_isInputSendMessage; private readonly CachedProperty _text; private readonly CachedProperty _TextData; public TextArea2DComponentManipulator() { FieldInfo field = UnityTypes.AdvPage.ClrType.GetField("textData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); set_textData = CustomFastReflectionHelper.CreateFastFieldSetter(field); FieldInfo field2 = UnityTypes.AdvPage.ClrType.GetField("status", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); set_status = CustomFastReflectionHelper.CreateFastFieldSetter(field2); FieldInfo field3 = UnityTypes.AdvPage.ClrType.GetField("isInputSendMessage", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); set_isInputSendMessage = CustomFastReflectionHelper.CreateFastFieldSetter(field3); FieldInfo field4 = UnityTypes.AdvPage.ClrType.GetField("nameText", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); set_nameText = CustomFastReflectionHelper.CreateFastFieldSetter(field4); _text = ReflectionCache.CachedProperty(UnityTypes.TextArea2D.ClrType, "text"); _TextData = ReflectionCache.CachedProperty(UnityTypes.TextArea2D.ClrType, "TextData"); } public string GetText(object ui) { object obj = _TextData.Get(ui); if (obj != null) { return ExtensionDataHelper.GetExtensionData(obj); } return (string)_text.Get(ui); } public void SetText(object ui, string text) { if (UnityTypes.AdvUiMessageWindow != null && UnityTypes.AdvPage != null) { Object val = Object.FindObjectOfType(UnityTypes.AdvUiMessageWindow.UnityType); object objA = AdvUiMessageWindow_Fields.text.Get((object)val); object objA2 = AdvUiMessageWindow_Fields.nameText.Get((object)val); if (object.Equals(objA, ui)) { Object arg = Object.FindObjectOfType(UnityTypes.AdvPage.UnityType); object obj = Activator.CreateInstance(UnityTypes.TextData.ClrType, text); _TextData.Set(ui, obj); set_textData(arg, obj); set_status(arg, 0); set_isInputSendMessage(arg, arg2: false); return; } if (object.Equals(objA2, ui)) { Object arg2 = Object.FindObjectOfType(UnityTypes.AdvPage.UnityType); object obj2 = Activator.CreateInstance(UnityTypes.TextData.ClrType, text); _TextData.Set(ui, obj2); set_nameText(arg2, text); return; } } object obj3 = Activator.CreateInstance(UnityTypes.TextData.ClrType, text); _text.Set(ui, (object)text); _TextData.Set(ui, obj3); } } internal class UguiNovelTextComponentManipulator : ITextComponentManipulator { private static readonly string TextPropertyName = "text"; private readonly Type _type; private readonly CachedProperty _property; public UguiNovelTextComponentManipulator(Type type) { _type = type; _property = ReflectionCache.CachedProperty(type, TextPropertyName); } public string GetText(object ui) { return (string)_property.Get(ui); } public void SetText(object ui, string text) { _property.Set(ui, (object)text); UguiNovelText_Methods.SetAllDirty.Invoke(ui); object obj = UguiNovelText_Properties.TextGenerator.Get(ui); UguiNovelTextGenerator_Methods.Refresh.Invoke(obj); } } } namespace XUnity.AutoTranslator.Plugin.Core.Textures { internal interface ITextureLoader { void Load(Texture2D texture, byte[] data); bool Verify(); } internal static class TextureLoader { private static readonly Dictionary Loaders; static TextureLoader() { Loaders = new Dictionary(); Register(ImageFormat.PNG, new LoadImageImageLoader()); if (Register(ImageFormat.TGA, new TgaImageLoader())) { _ = 1; } else Register(ImageFormat.TGA, new FallbackTgaImageLoader()); } public static bool Register(ImageFormat format, ITextureLoader loader) { try { if (loader.Verify()) { Loaders[format] = loader; return true; } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An image loader could not be registered."); } return false; } public static void Load(Texture2D texture, byte[] data, ImageFormat imageFormat) { if (Loaders.TryGetValue(imageFormat, out var value)) { value.Load(texture, data); } } } } namespace XUnity.AutoTranslator.Plugin.Core.Managed.Textures { internal class FallbackTgaImageLoader : ITextureLoader { public void Load(Texture2D texture, byte[] data) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_018b: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null && data == null) { return; } TextureFormat format = texture.format; using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); binaryReader.BaseStream.Seek(12L, SeekOrigin.Begin); short num = binaryReader.ReadInt16(); short num2 = binaryReader.ReadInt16(); int num3 = binaryReader.ReadByte(); binaryReader.BaseStream.Seek(1L, SeekOrigin.Current); Color[] array = (Color[])(object)new Color[num * num2]; if ((int)format == 3) { if (num3 == 32) { for (int i = 0; i < num * num2; i++) { float num4 = (float)(int)binaryReader.ReadByte() / 255f; float num5 = (float)(int)binaryReader.ReadByte() / 255f; float num6 = (float)(int)binaryReader.ReadByte() / 255f; binaryReader.ReadByte(); array[i] = new Color(num6, num5, num4, 1f); } } else { for (int j = 0; j < num * num2; j++) { float num7 = (float)(int)binaryReader.ReadByte() / 255f; float num8 = (float)(int)binaryReader.ReadByte() / 255f; float num9 = (float)(int)binaryReader.ReadByte() / 255f; array[j] = new Color(num9, num8, num7, 1f); } } } else if (num3 == 32) { for (int k = 0; k < num * num2; k++) { float num10 = (float)(int)binaryReader.ReadByte() / 255f; float num11 = (float)(int)binaryReader.ReadByte() / 255f; float num12 = (float)(int)binaryReader.ReadByte() / 255f; float num13 = (float)(int)binaryReader.ReadByte() / 255f; array[k] = new Color(num12, num11, num10, num13); } } else { for (int l = 0; l < num * num2; l++) { float num14 = (float)(int)binaryReader.ReadByte() / 255f; float num15 = (float)(int)binaryReader.ReadByte() / 255f; float num16 = (float)(int)binaryReader.ReadByte() / 255f; array[l] = new Color(num16, num15, num14, 1f); } } texture.SetPixels(array); texture.Apply(); } public bool Verify() { Load(null, null); return true; } } internal class LoadImageImageLoader : ITextureLoader { public void Load(Texture2D texture, byte[] data) { if (ImageConversion_Methods.LoadImage != null) { ImageConversion_Methods.LoadImage(texture, data, arg3: false); } else if (Texture2D_Methods.LoadImage != null) { Texture2D_Methods.LoadImage(texture, data); } } public bool Verify() { if (Texture2D_Methods.LoadImage == null) { return ImageConversion_Methods.LoadImage != null; } return true; } } internal class TgaImageLoader : ITextureLoader { public void Load(Texture2D texture, byte[] data) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Invalid comparison between Unknown and I4 //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null && data == null) { return; } TextureFormat format = texture.format; using MemoryStream input = new MemoryStream(data); using BinaryReader binaryReader = new BinaryReader(input); binaryReader.BaseStream.Seek(12L, SeekOrigin.Begin); short num = binaryReader.ReadInt16(); short num2 = binaryReader.ReadInt16(); int num3 = binaryReader.ReadByte(); binaryReader.BaseStream.Seek(1L, SeekOrigin.Current); Color32[] array = (Color32[])(object)new Color32[num * num2]; if ((int)format == 3) { if (num3 == 32) { for (int i = 0; i < num * num2; i++) { byte b = binaryReader.ReadByte(); byte b2 = binaryReader.ReadByte(); byte b3 = binaryReader.ReadByte(); binaryReader.ReadByte(); array[i] = Color32.op_Implicit(new Color((float)(int)b3, (float)(int)b2, (float)(int)b, 1f)); } } else { for (int j = 0; j < num * num2; j++) { byte b4 = binaryReader.ReadByte(); byte b5 = binaryReader.ReadByte(); byte b6 = binaryReader.ReadByte(); array[j] = Color32.op_Implicit(new Color((float)(int)b6, (float)(int)b5, (float)(int)b4, 1f)); } } } else if (num3 == 32) { for (int k = 0; k < num * num2; k++) { byte b7 = binaryReader.ReadByte(); byte b8 = binaryReader.ReadByte(); byte b9 = binaryReader.ReadByte(); byte b10 = binaryReader.ReadByte(); array[k] = Color32.op_Implicit(new Color((float)(int)b9, (float)(int)b8, (float)(int)b7, (float)(int)b10)); } } else { for (int l = 0; l < num * num2; l++) { byte b11 = binaryReader.ReadByte(); byte b12 = binaryReader.ReadByte(); byte b13 = binaryReader.ReadByte(); array[l] = Color32.op_Implicit(new Color((float)(int)b13, (float)(int)b12, (float)(int)b11, 1f)); } } texture.SetPixels32(array); texture.Apply(); } public bool Verify() { Load(null, null); return true; } } } namespace XUnity.AutoTranslator.Plugin.Core.Utilities { internal static class TextGetterCompatModeHelper { public static bool IsGettingText; [MethodImpl(MethodImplOptions.NoInlining)] public static void ReplaceTextWithOriginal(object instance, ref string __result) { if (!Settings.TextGetterCompatibilityMode || IsGettingText) { return; } TextTranslationInfo textTranslationInfo = instance.GetTextTranslationInfo(); if (textTranslationInfo == null || !textTranslationInfo.IsTranslated) { return; } Assembly assembly = instance.GetType().Assembly; if (assembly.IsAssemblyCsharp()) { __result = textTranslationInfo.OriginalText; return; } Assembly obj = new StackFrame(4).GetMethod().DeclaringType?.Assembly; if (!assembly.Equals(obj)) { __result = textTranslationInfo.OriginalText; } } } internal static class ClipboardHelper { public static void CopyToClipboard(IEnumerable lines, int maxCharacters) { List list = lines.ToList(); StringBuilder stringBuilder = new StringBuilder(); for (int i = 0; i < list.Count; i++) { string text = list[i]; if (text.Length + stringBuilder.Length > maxCharacters) { break; } if (i == list.Count - 1) { stringBuilder.Append(text); } else { stringBuilder.AppendLine(text); } } CopyToClipboard(stringBuilder.ToString()); } public static void CopyToClipboard(string text) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) try { TextEditor val = (TextEditor)GUIUtility.GetStateObject(typeof(TextEditor), GUIUtility.keyboardControl); val.text = text; val.SelectAll(); val.Copy(); } catch (Exception ex) { XuaLogger.Common.Error(ex, "An error while copying text to clipboard."); } } } internal static class ComponentHelper { public static T[] FindObjectsOfType() where T : Object { Object[] array = Object.FindObjectsOfType(typeof(T)); if (array == null) { return null; } T[] array2 = new T[array.Length]; T val = default(T); for (int i = 0; i < array2.Length; i++) { ObjectExtensions.TryCastTo((object)array[i], ref val); array2[i] = val; } return array2; } public static Texture2D CreateEmptyTexture2D(TextureFormat originalTextureFormat) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Invalid comparison between Unknown and I4 //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) TextureFormat val = (((int)originalTextureFormat == 3) ? ((TextureFormat)3) : (((int)originalTextureFormat == 10) ? ((TextureFormat)3) : (((int)originalTextureFormat != 12) ? ((TextureFormat)5) : ((TextureFormat)5)))); return new Texture2D(2, 2, val, false); } } public static class CoroutineHelper { public static WaitForSeconds CreateWaitForSeconds(float seconds) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown return new WaitForSeconds(seconds); } public static object CreateWaitForSecondsRealtime(float delay) { if (UnityFeatures.SupportsWaitForSecondsRealtime) { return GetWaitForSecondsRealtimeInternal(delay); } return null; } private static object GetWaitForSecondsRealtimeInternal(float delay) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown return (object)new WaitForSecondsRealtime(delay); } public static Coroutine Start(IEnumerator coroutine) { return PluginLoader.MonoBehaviour.StartCoroutine(coroutine); } public static void Stop(Coroutine coroutine) { PluginLoader.MonoBehaviour.StopCoroutine(coroutine); } } internal class DebounceFunction { [CompilerGenerated] private sealed class d__5 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public DebounceFunction <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__5(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; DebounceFunction debounceFunction = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = CoroutineHelper.CreateWaitForSeconds(debounceFunction._delaySeconds); <>1__state = 1; return true; case 1: <>1__state = -1; debounceFunction._callback(); debounceFunction._current = null; return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private readonly float _delaySeconds; private readonly Action _callback; private Coroutine _current; public DebounceFunction(float delaySeconds, Action callback) { _delaySeconds = delaySeconds; _callback = callback; } public void Execute() { if (_current != null) { CoroutineHelper.Stop(_current); } _current = CoroutineHelper.Start(Run()); } private IEnumerator Run() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__5(0) { <>4__this = this }; } } internal static class DirectoryHelper { public static string Parameterize(this string path) { if (Settings.ApplicationName != null) { return path.Replace("{lang}", Settings.Language).Replace("{Lang}", Settings.Language).Replace("{GameExeName}", Settings.ApplicationName); } return path; } } internal static class EnumHelper { public static string GetNames(Type flagType, object value) { if ((FlagsAttribute)flagType.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).FirstOrDefault() == null) { return Enum.GetName(flagType, value); } Array values = Enum.GetValues(flagType); string[] names = Enum.GetNames(flagType); string text = string.Empty; string[] array = names; foreach (string text2 in array) { object objA = Enum.Parse(flagType, text2, ignoreCase: true); foreach (object item in values) { long num = Convert.ToInt64(item); if ((Convert.ToInt64(value) & num) != 0L && object.Equals(objA, item)) { text = text + text2 + ";"; break; } } } if (text.EndsWith(";")) { text = text.Substring(0, text.Length - 1); } return text; } public static object GetValues(Type flagType, string commaSeparatedStringValue) { if ((FlagsAttribute)flagType.GetCustomAttributes(typeof(FlagsAttribute), inherit: false).FirstOrDefault() == null) { return Enum.Parse(flagType, commaSeparatedStringValue, ignoreCase: true); } string[] array = commaSeparatedStringValue.Split(new char[2] { ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); Array values = Enum.GetValues(flagType); Enum.GetUnderlyingType(flagType); long num = 0L; string[] array2 = array; foreach (string text in array2) { bool flag = false; foreach (object item in values) { string name = Enum.GetName(flagType, item); if (string.Equals(text, name, StringComparison.OrdinalIgnoreCase)) { long num2 = Convert.ToInt64(item); num |= num2; flag = true; } } if (!flag) { throw new ArgumentException("Requested value '" + text + "' was not found."); } } return Convert.ChangeType(num, Enum.GetUnderlyingType(flagType)); } } internal static class HashHelper { private static readonly SHA1Managed SHA1 = new SHA1Managed(); private static readonly uint[] Lookup32 = CreateLookup32(); public static string Compute(byte[] data) { return ByteArrayToHexViaLookup32(SHA1.ComputeHash(data)).Substring(0, 10); } private static uint[] CreateLookup32() { uint[] array = new uint[256]; for (int i = 0; i < 256; i++) { string text = i.ToString("X2"); array[i] = text[0] + ((uint)text[1] << 16); } return array; } private static string ByteArrayToHexViaLookup32(byte[] bytes) { uint[] lookup = Lookup32; char[] array = new char[bytes.Length * 2]; for (int i = 0; i < bytes.Length; i++) { uint num = lookup[bytes[i]]; array[2 * i] = (char)num; array[2 * i + 1] = (char)(num >> 16); } return new string(array); } } public static class JsonHelper { public static string Unescape(string str) { if (str == null) { return null; } StringBuilder stringBuilder = new StringBuilder(str); bool flag = false; for (int i = 0; i < stringBuilder.Length; i++) { char c = stringBuilder[i]; if (flag) { bool flag2 = true; char c2 = '\0'; switch (c) { case 'b': c2 = '\b'; break; case 'f': c2 = '\f'; break; case 'n': c2 = '\n'; break; case 'r': c2 = '\r'; break; case 't': c2 = '\t'; break; case '"': c2 = '"'; break; case '\\': c2 = '\\'; break; case 'u': c2 = 'u'; break; default: flag2 = false; break; } if (flag2) { if (c2 == 'u') { char value = (char)int.Parse(new string(new char[4] { stringBuilder[i + 1], stringBuilder[i + 2], stringBuilder[i + 3], stringBuilder[i + 4] }), NumberStyles.HexNumber); stringBuilder.Remove(--i, 6); stringBuilder.Insert(i, value); } else { stringBuilder.Remove(--i, 2); stringBuilder.Insert(i, c2); } } flag = false; } else if (c == '\\') { flag = true; } } return stringBuilder.ToString(); } public static string Escape(string str) { if (str == null || str.Length == 0) { return ""; } int length = str.Length; StringBuilder stringBuilder = new StringBuilder(length + 4); for (int i = 0; i < length; i++) { char c = str[i]; switch (c) { case '"': case '\\': stringBuilder.Append('\\'); stringBuilder.Append(c); break; case '\b': stringBuilder.Append("\\b"); break; case '\t': stringBuilder.Append("\\t"); break; case '\n': stringBuilder.Append("\\n"); break; case '\f': stringBuilder.Append("\\f"); break; case '\r': stringBuilder.Append("\\r"); break; case '\u0085': stringBuilder.Append("\\u0085"); break; case '\u2028': stringBuilder.Append("\\u2028"); break; case '\u2029': stringBuilder.Append("\\u2029"); break; default: stringBuilder.Append(c); break; } } return stringBuilder.ToString(); } } public static class LanguageHelper { internal static bool HasRedirectedTexts = false; private const string MogolianVowelSeparatorString = "\u180e"; private const char MogolianVowelSeparatorCharacter = '\u180e'; private static Func DefaultSymbolCheck; private static readonly Dictionary> LanguageSymbolChecks = new Dictionary>(StringComparer.OrdinalIgnoreCase) { { "ja", ContainsJapaneseSymbols }, { "ru", ContainsRussianSymbols }, { "zh-CN", ContainsChineseSymbols }, { "zh-TW", ContainsChineseSymbols }, { "zh-Hans", ContainsChineseSymbols }, { "zh-Hant", ContainsChineseSymbols }, { "zh", ContainsChineseSymbols }, { "ko", ContainsKoreanSymbols }, { "en", ContainsStandardLatinSymbols }, { "auto", (string text) => true } }; private static readonly HashSet LanguagesNotUsingWhitespaceBetweenWords = new HashSet { "ja", "zh", "zh-CN", "zh-TW", "zh-Hans", "zh-Hant" }; internal static bool RequiresWhitespaceUponLineMerging(string code) { return !LanguagesNotUsingWhitespaceBetweenWords.Contains(code); } internal static Func GetSymbolCheck(string language) { if (LanguageSymbolChecks.TryGetValue(language, out var value)) { return value; } return (string text) => true; } internal static bool ContainsLanguageSymbolsForSourceLanguage(string text) { if (DefaultSymbolCheck == null) { DefaultSymbolCheck = GetSymbolCheck(Settings.FromLanguage); } return DefaultSymbolCheck(text); } public static bool ContainsVariableSymbols(string text) { int num = text.IndexOf('{'); if (num > -1) { return text.IndexOf('}', num) > num; } return false; } public static bool IsRedirected(this string text) { if (text.Length > 0) { RedirectedResourceDetection redirectedResourceDetectionStrategy = Settings.RedirectedResourceDetectionStrategy; if (redirectedResourceDetectionStrategy != 0 && (uint)(redirectedResourceDetectionStrategy - 1) <= 2u) { return text.Contains("\u180e"); } return false; } return false; } public static string FixRedirected(this string text) { switch (Settings.RedirectedResourceDetectionStrategy) { case RedirectedResourceDetection.AppendMongolianVowelSeparatorAndRemoveAppended: if (text.Length > 0 && text[text.Length - 1] == '\u180e') { return text.Substring(0, text.Length - 1); } return text; case RedirectedResourceDetection.AppendMongolianVowelSeparatorAndRemoveAll: return text.Replace("\u180e", string.Empty); default: return text; } } public static string MakeRedirected(this string text) { RedirectedResourceDetection redirectedResourceDetectionStrategy = Settings.RedirectedResourceDetectionStrategy; if (redirectedResourceDetectionStrategy != 0 && (uint)(redirectedResourceDetectionStrategy - 1) <= 2u && (ContainsLanguageSymbolsForSourceLanguage(text) || ContainsVariableSymbols(text))) { HasRedirectedTexts = Settings.RedirectedResourceDetectionStrategy != RedirectedResourceDetection.None; return text + "\u180e"; } return text; } public static bool IsTranslatable(string text) { if (ContainsLanguageSymbolsForSourceLanguage(text)) { return !Settings.IgnoreTextStartingWith.Any((string x) => StringExtensions.StartsWithStrict(text, x)); } return false; } internal static bool ContainsJapaneseSymbols(string text) { foreach (char c in text) { if ((c >= '〡' && c <= '〩') || (c >= '〱' && c <= '〵') || (c >= 'ぁ' && c <= 'ゖ') || (c >= 'ァ' && c <= 'ヺ') || (c >= 'ヲ' && c <= 'ン') || (c >= '一' && c <= '龯') || (c >= '㐀' && c <= '䶿') || (c >= '豈' && c <= '\ufaff')) { return true; } } return false; } internal static bool ContainsKoreanSymbols(string text) { foreach (char c in text) { if (c >= '가' && c <= '\ud7af') { return true; } } return false; } internal static bool ContainsChineseSymbols(string text) { foreach (char c in text) { if ((c >= '一' && c <= '龯') || (c >= '㐀' && c <= '䶿') || (c >= '豈' && c <= '\ufaff')) { return true; } } return false; } internal static bool ContainsRussianSymbols(string text) { foreach (char c in text) { if ((c >= 'Ѐ' && c <= 'ӿ') || (c >= 'Ԁ' && c <= 'ԯ') || (c >= '\u2de0' && c <= '\u2dff') || (c >= 'Ꙁ' && c <= '\ua69f') || (c >= 'ᲀ' && c <= 'ᲈ') || (c >= '\ufe2e' && c <= '\ufe2f') || c == 'ᴫ' || c == 'ᵸ') { return true; } } return false; } internal static bool ContainsStandardLatinSymbols(string text) { foreach (char c in text) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { return true; } } return false; } } internal static class RomanizationHelper { public static string PostProcess(string text, TextPostProcessing postProcessing) { if ((postProcessing & TextPostProcessing.ReplaceHtmlEntities) != 0) { text = XUnity.AutoTranslator.Plugin.Core.Shims.WebUtility.HtmlDecode(text); } if ((postProcessing & TextPostProcessing.ReplaceMacronWithCircumflex) != 0) { text = ConvertMacronToCircumflex(text); } if ((postProcessing & TextPostProcessing.RemoveAllDiacritics) != 0) { text = DiacriticHelper.RemoveAllDiacritics(text); } if ((postProcessing & TextPostProcessing.RemoveApostrophes) != 0) { text = RemoveNApostrophe(text); } if ((postProcessing & TextPostProcessing.ReplaceWideCharacters) != 0) { text = ReplaceWideCharacters(text); } return text; } public static string ReplaceWideCharacters(string input) { StringBuilder stringBuilder = new StringBuilder(input); int length = input.Length; bool flag = false; for (int i = 0; i < length; i++) { char c = stringBuilder[i]; if (c >= '\uff00' && c <= '~') { flag = true; stringBuilder[i] = (char)(c - 65248); } if (c == '\u3000') { flag = true; stringBuilder[i] = ' '; } } if (!flag) { return input; } return stringBuilder.ToString(); } public static string ConvertMacronToCircumflex(string romanizedJapaneseText) { StringBuilder stringBuilder = new StringBuilder(romanizedJapaneseText.Length); foreach (char c in romanizedJapaneseText) { switch (c) { case 'Ā': stringBuilder.Append('Â'); break; case 'ā': stringBuilder.Append('â'); break; case 'Ī': stringBuilder.Append('Î'); break; case 'ī': stringBuilder.Append('î'); break; case 'Ū': stringBuilder.Append('Û'); break; case 'ū': stringBuilder.Append('û'); break; case 'Ē': stringBuilder.Append('Ê'); break; case 'ē': stringBuilder.Append('ê'); break; case 'Ō': stringBuilder.Append('Ô'); break; case 'ō': stringBuilder.Append('ô'); break; default: stringBuilder.Append(c); break; } } return stringBuilder.ToString(); } public static string RemoveNApostrophe(string romanizedJapaneseText) { return romanizedJapaneseText.Replace("n'", "n").Replace("n’", "n"); } } internal static class TemplatingHelper { public static bool ContainsUntemplatedCharacters(string text) { bool flag = false; int length = text.Length; for (int i = 0; i < length; i++) { char c = text[i]; if (flag) { if (c == '}') { int num = i + 1; if (num < length && text[num] == '}') { i++; flag = false; } } } else if (c == '{') { int num2 = i + 1; if (num2 < length && text[num2] == '{') { i++; flag = true; } } else if (!char.IsWhiteSpace(c)) { return true; } } return false; } public static TemplatedString TemplatizeByReplacementsAndNumbers(this string str) { TemplatedString templatedString = str.TemplatizeByReplacements(); if (templatedString == null) { return str.TemplatizeByNumbers(); } return templatedString.Template.TemplatizeByNumbers(templatedString); } public static TemplatedString TemplatizeByReplacements(this string str) { if (Settings.Replacements.Count == 0) { return null; } Dictionary dictionary = new Dictionary(); char c = 'A'; bool flag = false; foreach (KeyValuePair replacement in Settings.Replacements) { string key = replacement.Key; string value = replacement.Value; if (string.IsNullOrEmpty(value)) { int num = -1; while ((num = str.IndexOf(key, StringComparison.InvariantCulture)) != -1) { flag = true; str = str.Remove(num, key.Length); } continue; } string text = null; int num2 = -1; while ((num2 = str.IndexOf(key, StringComparison.InvariantCulture)) != -1) { if (text == null) { text = "{{" + c++ + "}}"; dictionary.Add(text, value); } str = str.Remove(num2, key.Length).Insert(num2, text); } } if (dictionary.Count > 0 || flag) { return new TemplatedString(str, dictionary); } return null; } public static bool IsNumberOrDotOrControl(char c) { if ('*' > c || c > ':') { if ('0' <= c) { return c <= '9'; } return false; } return true; } public static bool IsNumber(char c) { if ('0' > c || c > '9') { if ('0' <= c) { return c <= '9'; } return false; } return true; } public static TemplatedString TemplatizeByNumbers(this string str, TemplatedString existingTemplatedString = null) { int num = 0; if (existingTemplatedString != null) { num = existingTemplatedString.Arguments.Count; str = existingTemplatedString.Template; } Dictionary dictionary = new Dictionary(); bool flag = false; StringBuilder stringBuilder = null; char c = (char)(65 + num); int num2 = -1; int num3 = -1; for (int i = 0; i < str.Length; i++) { char c2 = str[i]; if (flag) { if (IsNumber(c2)) { num3 = i; } if (IsNumberOrDotOrControl(c2)) { stringBuilder.Append(c2); continue; } int num4 = i - num3 - 1; stringBuilder.Remove(stringBuilder.Length - num4, num4); string text = stringBuilder.ToString(); string text2 = "{{" + c + "}}"; dictionary.Add(text2, text); c = (char)(c + 1); stringBuilder = null; flag = false; str = str.Remove(num2, num3 - num2 + 1).Insert(num2, text2); i += text2.Length - text.Length; } else if (IsNumber(c2)) { flag = true; stringBuilder = new StringBuilder(); stringBuilder.Append(c2); num2 = i; num3 = i; } } if (stringBuilder != null) { int num5 = str.Length - num3 - 1; stringBuilder.Remove(stringBuilder.Length - num5, num5); string value = stringBuilder.ToString(); string text3 = "{{" + c + "}}"; dictionary.Add(text3, value); str = str.Remove(num2, str.Length - num2 - num5).Insert(num2, text3); } if (dictionary.Count > 0) { Dictionary dictionary2 = existingTemplatedString?.Arguments ?? dictionary; if (dictionary != dictionary2) { foreach (KeyValuePair item in dictionary) { dictionary2.Add(item.Key, item.Value); } } return new TemplatedString(str, dictionary2); } return existingTemplatedString; } } internal static class TextHelper { public static string Encode(string text) { return EscapeNewlines(text); } public static string[] ReadTranslationLineAndDecode(string str) { if (string.IsNullOrEmpty(str)) { return null; } string[] array = new string[2]; int num = 0; bool flag = false; int length = str.Length; StringBuilder stringBuilder = new StringBuilder((int)((double)length / 1.3)); for (int i = 0; i < length; i++) { char c = str[i]; if (flag) { switch (c) { case '=': case '\\': stringBuilder.Append(c); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 'u': if (i + 4 < length) { int num2 = int.Parse(new string(new char[4] { str[i + 1], str[i + 2], str[i + 3], str[i + 4] }), NumberStyles.HexNumber); stringBuilder.Append((char)num2); i += 4; break; } throw new Exception("Found invalid unicode in line: " + str); default: stringBuilder.Append('\\'); stringBuilder.Append(c); break; } flag = false; continue; } switch (c) { case '\\': flag = true; break; case '=': if (num > 1) { return null; } array[num++] = stringBuilder.ToString(); stringBuilder.Length = 0; break; case '%': if (i + 2 < length && str[i + 1] == '3' && str[i + 2] == 'D') { stringBuilder.Append('='); i += 2; } else { stringBuilder.Append(c); } break; case '/': { int num3 = i + 1; if (num3 < length && str[num3] == '/') { array[num++] = stringBuilder.ToString(); if (num == 2) { return array; } return null; } stringBuilder.Append(c); break; } default: stringBuilder.Append(c); break; } } if (num != 1) { return null; } array[num++] = stringBuilder.ToString(); return array; } internal static string EscapeNewlines(string str) { if (str == null || str.Length == 0) { return ""; } int length = str.Length; StringBuilder stringBuilder = new StringBuilder(length + 4); for (int i = 0; i < length; i++) { char c = str[i]; switch (c) { case '/': { int num = i + 1; if (num < length && str[num] == '/') { stringBuilder.Append('\\'); stringBuilder.Append(c); stringBuilder.Append('\\'); stringBuilder.Append(c); i++; } else { stringBuilder.Append(c); } break; } case '\\': stringBuilder.Append('\\'); stringBuilder.Append(c); break; case '=': stringBuilder.Append('\\'); stringBuilder.Append(c); break; case '\n': stringBuilder.Append("\\n"); break; case '\r': stringBuilder.Append("\\r"); break; default: stringBuilder.Append(c); break; } } return stringBuilder.ToString(); } } internal static class UtageHelper { private static object AdvManager; private static HashSet Labels = new HashSet(); public static void FixLabel(ref string label) { object[] index = new object[0]; if (AdvManager == null && UnityTypes.AdvDataManager != null) { try { AdvManager = Object.FindObjectOfType(UnityTypes.AdvDataManager.UnityType); IEnumerable enumerable = default(IEnumerable); ObjectExtensions.TryCastTo(UnityTypes.AdvDataManager.ClrType.GetProperty("ScenarioDataTbl").GetValue(AdvManager, index), ref enumerable); IEnumerable enumerable2 = default(IEnumerable); foreach (object item3 in enumerable) { Type type = item3.GetType(); string item = (string)type.GetProperty("Key").GetValue(item3, index); Labels.Add(item); object value = type.GetProperty("Value").GetValue(item3, index); if (value == null) { continue; } ObjectExtensions.TryCastTo(value.GetType().GetProperty("ScenarioLabels").GetValue(value, index), ref enumerable2); foreach (object item4 in enumerable2) { string item2 = (string)item4.GetType().GetProperty("Key").GetValue(item4, index); Labels.Add(item2); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while setting up scenario set."); } } if (!Labels.Contains(label)) { int scope = TranslationScopeHelper.GetScope(null); if (AutoTranslationPlugin.Current.TextCache.TryGetReverseTranslation(label, scope, out var key)) { label = key; } } } } } namespace XUnity.AutoTranslator.Plugin.Core.Shims { public abstract class CustomYieldInstructionShim : IEnumerator { [CompilerGenerated] private sealed class d__17 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public CustomYieldInstructionShim <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__17(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; CustomYieldInstructionShim customYieldInstructionShim = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; if (UnityFeatures.SupportsCustomYieldInstruction) { <>2__current = customYieldInstructionShim; <>1__state = 1; return true; } goto IL_0069; case 1: <>1__state = -1; break; case 2: { <>1__state = -1; goto IL_0069; } IL_0069: if (customYieldInstructionShim.DetermineKeepWaiting()) { <>2__current = CoroutineHelper.CreateWaitForSeconds(0.2f); <>1__state = 2; return true; } break; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private float? _startTime; public object Current => null; public abstract bool keepWaiting { get; } public float? InGameTimeout { get; set; } public bool IsTimedOut { get; set; } internal bool DetermineKeepWaiting() { if (!keepWaiting || IsTimedOut) { return false; } if (InGameTimeout.HasValue) { if (!_startTime.HasValue) { _startTime = TimeSupport.Time.realtimeSinceStartup; } float value = _startTime.Value; if (TimeSupport.Time.realtimeSinceStartup - value > InGameTimeout) { IsTimedOut = true; return false; } } return true; } public bool MoveNext() { return DetermineKeepWaiting(); } public void Reset() { } public IEnumerator GetSupportedEnumerator() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__17(0) { <>4__this = this }; } } internal static class WebUtility { private static class HtmlEntities { private static string[] _entitiesList = new string[253] { "\"-quot", "&-amp", "'-apos", "<-lt", ">-gt", "\u00a0-nbsp", "¡-iexcl", "¢-cent", "£-pound", "¤-curren", "¥-yen", "¦-brvbar", "§-sect", "\u00a8-uml", "©-copy", "ª-ordf", "«-laquo", "¬-not", "\u00ad-shy", "®-reg", "\u00af-macr", "°-deg", "±-plusmn", "²-sup2", "³-sup3", "\u00b4-acute", "µ-micro", "¶-para", "·-middot", "\u00b8-cedil", "¹-sup1", "º-ordm", "»-raquo", "¼-frac14", "½-frac12", "¾-frac34", "¿-iquest", "À-Agrave", "Á-Aacute", "Â-Acirc", "Ã-Atilde", "Ä-Auml", "Å-Aring", "Æ-AElig", "Ç-Ccedil", "È-Egrave", "É-Eacute", "Ê-Ecirc", "Ë-Euml", "Ì-Igrave", "Í-Iacute", "Î-Icirc", "Ï-Iuml", "Ð-ETH", "Ñ-Ntilde", "Ò-Ograve", "Ó-Oacute", "Ô-Ocirc", "Õ-Otilde", "Ö-Ouml", "×-times", "Ø-Oslash", "Ù-Ugrave", "Ú-Uacute", "Û-Ucirc", "Ü-Uuml", "Ý-Yacute", "Þ-THORN", "ß-szlig", "à-agrave", "á-aacute", "â-acirc", "ã-atilde", "ä-auml", "å-aring", "æ-aelig", "ç-ccedil", "è-egrave", "é-eacute", "ê-ecirc", "ë-euml", "ì-igrave", "í-iacute", "î-icirc", "ï-iuml", "ð-eth", "ñ-ntilde", "ò-ograve", "ó-oacute", "ô-ocirc", "õ-otilde", "ö-ouml", "÷-divide", "ø-oslash", "ù-ugrave", "ú-uacute", "û-ucirc", "ü-uuml", "ý-yacute", "þ-thorn", "ÿ-yuml", "Œ-OElig", "œ-oelig", "Š-Scaron", "š-scaron", "Ÿ-Yuml", "ƒ-fnof", "ˆ-circ", "\u02dc-tilde", "Α-Alpha", "Β-Beta", "Γ-Gamma", "Δ-Delta", "Ε-Epsilon", "Ζ-Zeta", "Η-Eta", "Θ-Theta", "Ι-Iota", "Κ-Kappa", "Λ-Lambda", "Μ-Mu", "Ν-Nu", "Ξ-Xi", "Ο-Omicron", "Π-Pi", "Ρ-Rho", "Σ-Sigma", "Τ-Tau", "Υ-Upsilon", "Φ-Phi", "Χ-Chi", "Ψ-Psi", "Ω-Omega", "α-alpha", "β-beta", "γ-gamma", "δ-delta", "ε-epsilon", "ζ-zeta", "η-eta", "θ-theta", "ι-iota", "κ-kappa", "λ-lambda", "μ-mu", "ν-nu", "ξ-xi", "ο-omicron", "π-pi", "ρ-rho", "ς-sigmaf", "σ-sigma", "τ-tau", "υ-upsilon", "φ-phi", "χ-chi", "ψ-psi", "ω-omega", "ϑ-thetasym", "ϒ-upsih", "ϖ-piv", "\u2002-ensp", "\u2003-emsp", "\u2009-thinsp", "\u200c-zwnj", "\u200d-zwj", "\u200e-lrm", "\u200f-rlm", "–-ndash", "—-mdash", "‘-lsquo", "’-rsquo", "‚-sbquo", "“-ldquo", "”-rdquo", "„-bdquo", "†-dagger", "‡-Dagger", "•-bull", "…-hellip", "‰-permil", "′-prime", "″-Prime", "‹-lsaquo", "›-rsaquo", "‾-oline", "⁄-frasl", "€-euro", "ℑ-image", "℘-weierp", "ℜ-real", "™-trade", "ℵ-alefsym", "←-larr", "↑-uarr", "→-rarr", "↓-darr", "↔-harr", "↵-crarr", "⇐-lArr", "⇑-uArr", "⇒-rArr", "⇓-dArr", "⇔-hArr", "∀-forall", "∂-part", "∃-exist", "∅-empty", "∇-nabla", "∈-isin", "∉-notin", "∋-ni", "∏-prod", "∑-sum", "−-minus", "∗-lowast", "√-radic", "∝-prop", "∞-infin", "∠-ang", "∧-and", "∨-or", "∩-cap", "∪-cup", "∫-int", "∴-there4", "∼-sim", "≅-cong", "≈-asymp", "≠-ne", "≡-equiv", "≤-le", "≥-ge", "⊂-sub", "⊃-sup", "⊄-nsub", "⊆-sube", "⊇-supe", "⊕-oplus", "⊗-otimes", "⊥-perp", "⋅-sdot", "⌈-lceil", "⌉-rceil", "⌊-lfloor", "⌋-rfloor", "〈-lang", "〉-rang", "◊-loz", "♠-spades", "♣-clubs", "♥-hearts", "♦-diams" }; private static Dictionary _lookupTable = GenerateLookupTable(); private static Dictionary GenerateLookupTable() { Dictionary dictionary = new Dictionary(StringComparer.Ordinal); string[] entitiesList = _entitiesList; foreach (string text in entitiesList) { dictionary.Add(text.Substring(2), text[0]); } return dictionary; } public static char Lookup(string entity) { _lookupTable.TryGetValue(entity, out var value); return value; } } private const char HIGH_SURROGATE_START = '\ud800'; private const char LOW_SURROGATE_START = '\udc00'; private const char LOW_SURROGATE_END = '\udfff'; private const int UNICODE_PLANE00_END = 65535; private const int UNICODE_PLANE01_START = 65536; private const int UNICODE_PLANE16_END = 1114111; private static readonly char[] _htmlEntityEndingChars = new char[2] { ';', '&' }; private static bool StringRequiresHtmlDecoding(string s) { return s.IndexOf('&') >= 0; } private unsafe static int IndexOfHtmlEncodingChars(string s, int startPos) { int num = s.Length - startPos; fixed (char* ptr = s) { char* ptr2 = ptr + startPos; while (num > 0) { switch (*ptr2) { case '"': case '&': case '\'': case '<': case '>': return s.Length - num; } ptr2++; num--; } } return -1; } public static string HtmlEncode(string value) { if (string.IsNullOrEmpty(value)) { return value; } if (IndexOfHtmlEncodingChars(value, 0) == -1) { return value; } StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); HtmlEncode(value, stringWriter); return stringWriter.ToString(); } public unsafe static void HtmlEncode(string value, TextWriter output) { if (value == null) { return; } if (output == null) { throw new ArgumentNullException("output"); } int num = IndexOfHtmlEncodingChars(value, 0); if (num == -1) { output.Write(value); return; } int num2 = value.Length - num; fixed (char* ptr = value) { char* ptr2 = ptr; while (num-- > 0) { output.Write(*(ptr2++)); } while (num2 > 0) { char c = *ptr2; if (c <= '>') { switch (c) { case '<': output.Write("<"); break; case '>': output.Write(">"); break; case '"': output.Write("""); break; case '\'': output.Write("'"); break; case '&': output.Write("&"); break; default: output.Write(c); break; } } else { output.Write(c); } num2--; ptr2++; } } } public static string HtmlDecode(string value) { if (string.IsNullOrEmpty(value)) { return value; } if (!StringRequiresHtmlDecoding(value)) { return value; } StringWriter stringWriter = new StringWriter(CultureInfo.InvariantCulture); HtmlDecode(value, stringWriter); return stringWriter.ToString(); } private static void ConvertSmpToUtf16(uint smpChar, out char leadingSurrogate, out char trailingSurrogate) { int num = (int)(smpChar - 65536); leadingSurrogate = (char)(num / 1024 + 55296); trailingSurrogate = (char)(num % 1024 + 56320); } public static void HtmlDecode(string value, TextWriter output) { if (value == null) { return; } if (output == null) { throw new ArgumentNullException("output"); } if (!StringRequiresHtmlDecoding(value)) { output.Write(value); return; } int length = value.Length; for (int i = 0; i < length; i++) { char c = value[i]; if (c == '&') { int num = value.IndexOfAny(_htmlEntityEndingChars, i + 1); if (num > 0 && value[num] == ';') { string text = value.Substring(i + 1, num - i - 1); if (text.Length > 1 && text[0] == '#') { uint result; bool flag = ((text[1] != 'x' && text[1] != 'X') ? uint.TryParse(text.Substring(1), NumberStyles.Integer, NumberFormatInfo.InvariantInfo, out result) : uint.TryParse(text.Substring(2), NumberStyles.AllowHexSpecifier, NumberFormatInfo.InvariantInfo, out result)); if (flag) { flag = 0 < result && result <= 65535; } if (flag) { if (result <= 65535) { output.Write((char)result); } else { ConvertSmpToUtf16(result, out var leadingSurrogate, out var trailingSurrogate); output.Write(leadingSurrogate); output.Write(trailingSurrogate); } i = num; continue; } } else { i = num; char c2 = HtmlEntities.Lookup(text); if (c2 == '\0') { output.Write('&'); output.Write(text); output.Write(';'); continue; } c = c2; } } } output.Write(c); } } } } namespace XUnity.AutoTranslator.Plugin.Core.Properties { [GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [CompilerGenerated] [DebuggerNonUserCode] internal class Resources { private static ResourceManager resourceMan; private static CultureInfo resourceCulture; [EditorBrowsable(EditorBrowsableState.Advanced)] internal static ResourceManager ResourceManager { get { if (resourceMan == null) { resourceMan = new ResourceManager("XUnity.AutoTranslator.Plugin.Core.Properties.Resources", typeof(Resources).Assembly); } return resourceMan; } } [EditorBrowsable(EditorBrowsableState.Advanced)] internal static CultureInfo Culture { get { return resourceCulture; } set { resourceCulture = value; } } internal static string StaticTranslations => ResourceManager.GetString("StaticTranslations", resourceCulture); internal Resources() { } } } namespace XUnity.AutoTranslator.Plugin.Core.Parsing { internal class ArgumentedUntranslatedTextInfo { public string Key { get; set; } public UntranslatedTextInfo Info { get; set; } } internal class GameLogTextParser { public bool CanApply(object ui) { return ui.SupportsLineParser(); } public ParserResult Parse(string input, int scope, IReadOnlyTextTranslationCache cache) { StringReader stringReader = new StringReader(input); bool flag = false; StringBuilder stringBuilder = new StringBuilder(input.Length); List list = new List(); char c = 'A'; string text = null; while ((text = stringReader.ReadLine()) != null) { if (!string.IsNullOrEmpty(text)) { if (cache.IsTranslatable(text, isToken: true, scope)) { flag = true; string value = "[[" + c++ + "]]"; stringBuilder.Append(value).Append('\n'); list.Add(new ArgumentedUntranslatedTextInfo { Info = new UntranslatedTextInfo(text) }); } else { stringBuilder.Append(text).Append('\n'); } } else { stringBuilder.Append('\n'); } } if (!flag) { return null; } if (!input.EndsWith("\r\n") && !input.EndsWith("\n")) { stringBuilder.Remove(stringBuilder.Length - 1, 1); } if (list.Count > 1) { return new ParserResult(ParserResultOrigin.GameLogTextParser, input, stringBuilder.ToString(), allowPartialTranslation: false, cacheCombinedResult: false, persistCombinedResult: false, persistTokenResult: true, list); } return null; } } internal class ParserResult { private static readonly string IgnoredNameEnding = "_i"; public ParserResultOrigin Origin { get; } public string OriginalText { get; } public string TranslationTemplate { get; } public List Arguments { get; } public Match Match { get; } public Regex Regex { get; } public bool AllowPartialTranslation { get; } public bool CacheCombinedResult { get; } public bool PersistCombinedResult { get; } public bool PersistTokenResult { get; } public int Priority => (int)Origin; public ParserResult(ParserResultOrigin origin, string originalText, string template, bool allowPartialTranslation, bool cacheCombinedResult, bool persistCombinedResult, bool persistTokenResult, List args) { Origin = origin; OriginalText = originalText; TranslationTemplate = template; AllowPartialTranslation = allowPartialTranslation; CacheCombinedResult = cacheCombinedResult; PersistCombinedResult = persistCombinedResult; PersistTokenResult = persistTokenResult; Arguments = args; } public ParserResult(ParserResultOrigin origin, string originalText, string template, bool allowPartialTranslation, bool cacheCombinedResult, bool persistCombinedResult, bool persistTokenResult, Regex regex, Match match) { Origin = origin; OriginalText = originalText; TranslationTemplate = template; AllowPartialTranslation = allowPartialTranslation; CacheCombinedResult = cacheCombinedResult; PersistCombinedResult = persistCombinedResult; PersistTokenResult = persistTokenResult; Match = match; Regex = regex; } public string GetTranslationFromParts(Func getTranslation) { bool flag = true; StringBuilder stringBuilder = new StringBuilder(TranslationTemplate); if (Match != null) { GroupCollection groups = Match.Groups; string[] groupNames = Regex.GetGroupNames(); for (int num = groupNames.Length - 1; num > 0; num--) { string text = groupNames[num]; bool flag2 = text.EndsWith(IgnoredNameEnding); int.TryParse(text, NumberStyles.None, CultureInfo.InvariantCulture, out var result); Group group; string oldValue; if (result != 0) { group = groups[result]; oldValue = "$" + result; } else { group = groups[text]; oldValue = "${" + text + "}"; } if (group.Success) { string value = group.Value; string text2 = (flag2 ? RomanizationHelper.PostProcess(value, Settings.RegexPostProcessing) : getTranslation(new UntranslatedTextInfo(value))); if (text2 != null) { stringBuilder = stringBuilder.Replace(oldValue, text2); } else { flag = false; } } else { stringBuilder = stringBuilder.Replace(oldValue, string.Empty); } } } else { foreach (ArgumentedUntranslatedTextInfo argument in Arguments) { string text3 = getTranslation(argument.Info); if (text3 != null) { stringBuilder = stringBuilder.Replace(argument.Key, text3); } else { flag = false; } } } if (flag) { return stringBuilder.ToString(); } return null; } } internal enum ParserResultOrigin { RichTextParser, RegexTextParser, GameLogTextParser } internal class RegexSplittingTextParser { public bool CanApply(object ui) { return !ui.IsSpammingComponent(); } public ParserResult Parse(string input, int scope, IReadOnlyTextTranslationCache cache) { if (cache.TryGetTranslationSplitter(input, scope, out var match, out var splitter)) { return new ParserResult(ParserResultOrigin.RegexTextParser, input, splitter.Translation, allowPartialTranslation: true, cacheCombinedResult: true, Settings.CacheRegexPatternResults, persistTokenResult: true, splitter.CompiledRegex, match); } return null; } } internal class RegexTranslationSplitter { public Regex CompiledRegex { get; set; } public string Original { get; set; } public string Translation { get; set; } public string Key { get; set; } public string Value { get; set; } public RegexTranslationSplitter(string key, string value) { Key = key; Value = value; if (key.StartsWith("sr:")) { key = key.Substring(3, key.Length - 3); } int num = key.IndexOf('"'); if (num != -1) { num++; int num2 = key.LastIndexOf('"'); if (num2 == num - 1) { throw new Exception("Regex with key: '" + Key + "' starts with a \" but does not end with a \"."); } key = key.Substring(num, num2 - num); } if (value.StartsWith("sr:")) { value = value.Substring(3, value.Length - 3); } num = value.IndexOf('"'); if (num != -1) { num++; int num3 = value.LastIndexOf('"'); if (num3 == num - 1) { throw new Exception("Regex with value: '" + Value + "' starts with a \" but does not end with a \"."); } value = value.Substring(num, num3 - num); } if (!key.StartsWith("^")) { key = "^" + key; } if (!key.EndsWith("$")) { key += "$"; } CompiledRegex = new Regex(key, AutoTranslationPlugin.RegexCompiledSupportedFlag); Original = key; Translation = value; } } internal class RichTextParser { private static readonly char[] TagNameEnders = new char[2] { '=', ' ' }; private static readonly Regex TagRegex = new Regex("(<.*?>)", AutoTranslationPlugin.RegexCompiledSupportedFlag); private static readonly HashSet IgnoreTags = new HashSet { "ruby", "group" }; private static readonly HashSet KnownTags = new HashSet { "b", "i", "size", "color", "em", "sup", "sub", "dash", "space", "u", "strike", "param", "format", "emoji", "speed", "sound", "line-height" }; public bool CanApply(object ui) { if (Settings.HandleRichText) { return ui.SupportsRichText(); } return false; } private static bool IsAllLatin(string value, int endIdx) { for (int i = 0; i < endIdx; i++) { char c = value[i]; if ((c < 'A' || c > 'Z') && (c < 'a' || c > 'z') && c != '-' && c != '_') { return false; } } return true; } private static bool StartsWithPound(string value, int endIdx) { if (0 < value.Length) { return value[0] == '#'; } return false; } public ParserResult Parse(string input, int scope) { if (!Settings.HandleRichText) { return null; } List list = new List(); StringBuilder stringBuilder = new StringBuilder(input.Length); char c = 'A'; bool flag = false; string[] array = TagRegex.Split(input); foreach (string text in array) { if (text.Length <= 0) { continue; } bool flag2 = text[0] == '<' && text[text.Length - 1] == '>'; bool num = flag2 && text.Length > 1 && text[1] == '/'; string text2 = null; if (num) { text2 = text.Substring(2, text.Length - 3); } else if (flag2) { text2 = text.Substring(1, text.Length - 2); } if (flag2) { string[] array2 = text2.Split(TagNameEnders); string text3 = ((array2.Length < 2) ? text2 : array2[0]); int length = text3.Length; if (KnownTags.Contains(text3) || (IsAllLatin(text3, length) && !IgnoreTags.Contains(text3)) || StartsWithPound(text3, length)) { stringBuilder.Append(text); flag = false; } continue; } if (flag) { list[list.Count - 1].Info.UntranslatedText += text; } else { string text4 = "[[" + c++ + "]]"; ArgumentedUntranslatedTextInfo item = new ArgumentedUntranslatedTextInfo { Key = text4, Info = new UntranslatedTextInfo(text) }; list.Add(item); stringBuilder.Append(text4); } flag = true; } for (int j = 0; j < list.Count; j++) { ArgumentedUntranslatedTextInfo argumentedUntranslatedTextInfo = list[j]; for (int k = 0; k < j; k++) { string untranslatedText = list[k].Info.UntranslatedText; if (!StringExtensions.IsNullOrWhiteSpace(untranslatedText)) { argumentedUntranslatedTextInfo.Info.ContextBefore.Add(untranslatedText); } } for (int l = j + 1; l < list.Count; l++) { string untranslatedText2 = list[l].Info.UntranslatedText; if (!StringExtensions.IsNullOrWhiteSpace(untranslatedText2)) { argumentedUntranslatedTextInfo.Info.ContextAfter.Add(untranslatedText2); } } } string text5 = stringBuilder.ToString(); if (c == 'A' || text5.Length <= 5) { return null; } return new ParserResult(ParserResultOrigin.RichTextParser, input, text5, allowPartialTranslation: false, cacheCombinedResult: true, Settings.PersistRichTextMode == PersistRichTextMode.Final, Settings.PersistRichTextMode == PersistRichTextMode.Fragment, list); } } internal static class UnityTextParsers { public static RichTextParser RichTextParser; public static RegexSplittingTextParser RegexSplittingTextParser; public static GameLogTextParser GameLogTextParser; public static void Initialize() { RichTextParser = new RichTextParser(); RegexSplittingTextParser = new RegexSplittingTextParser(); GameLogTextParser = new GameLogTextParser(); } } } namespace XUnity.AutoTranslator.Plugin.Core.Hooks { internal static class FairyGUIHooks { public static readonly Type[] All = new Type[2] { typeof(TextField_text_Hook), typeof(TextField_htmlText_Hook) }; } [HookingHelperPriority(0)] internal static class TextField_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextField != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textField = UnityTypes.TextField; return AccessToolsShim.Property((textField != null) ? textField.ClrType : null, "text")?.GetSetMethod(); } private static void Postfix(object __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TextField_htmlText_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextField != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textField = UnityTypes.TextField; return AccessToolsShim.Property((textField != null) ? textField.ClrType : null, "htmlText")?.GetSetMethod(); } private static void Postfix(object __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } internal static class HooksSetup { private static bool _textAssetHooksInstalled = false; private static bool _installedPluginTranslationHooks = false; private static HashSet _installedAssemblies = new HashSet(); public static void InstallTextGetterCompatHooks() { try { if (Settings.TextGetterCompatibilityMode) { HookingHelper.PatchAll((IEnumerable)TextGetterCompatHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up text getter compat hooks."); } } public static void InstallImageHooks() { try { if (Settings.EnableTextureTranslation || Settings.EnableTextureDumping) { HookingHelper.PatchAll((IEnumerable)ImageHooks.All, Settings.ForceMonoModHooks); if (Settings.EnableLegacyTextureLoading || Settings.EnableSpriteHooking) { HookingHelper.PatchAll((IEnumerable)ImageHooks.Sprite, Settings.ForceMonoModHooks); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up image hooks."); } } public static void InstallSpriteRendererHooks() { try { if (Settings.EnableSpriteRendererHooking && (Settings.EnableTextureTranslation || Settings.EnableTextureDumping)) { HookingHelper.PatchAll((IEnumerable)ImageHooks.SpriteRenderer, Settings.ForceMonoModHooks); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up image hooks."); } } public static void InstallTextAssetHooks() { try { if (!_textAssetHooksInstalled) { _textAssetHooksInstalled = true; HookingHelper.PatchAll((IEnumerable)TextAssetHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up text asset hooks."); } } public static void InstallTextHooks() { try { if (Settings.EnableUGUI) { HookingHelper.PatchAll((IEnumerable)UGUIHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up hooks for UGUI."); } try { if (Settings.EnableUIElements) { HookingHelper.PatchAll((IEnumerable)UIElementsHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while setting up hooks for UIElements."); } try { if (Settings.EnableTextMeshPro) { HookingHelper.PatchAll((IEnumerable)TextMeshProHooks.All, Settings.ForceMonoModHooks); if (Settings.DisableTextMeshProScrollInEffects) { HookingHelper.PatchAll((IEnumerable)TextMeshProHooks.DisableScrollInTmp, Settings.ForceMonoModHooks); } } } catch (Exception ex3) { XuaLogger.AutoTranslator.Error(ex3, "An error occurred while setting up hooks for TextMeshPro."); } try { if (Settings.EnableNGUI) { HookingHelper.PatchAll((IEnumerable)NGUIHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex4) { XuaLogger.AutoTranslator.Error(ex4, "An error occurred while setting up hooks for NGUI."); } try { if (Settings.EnableIMGUI) { HookingHelper.PatchAll((IEnumerable)IMGUIHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex5) { XuaLogger.AutoTranslator.Error(ex5, "An error occurred while setting up hooks for IMGUI."); } try { HookingHelper.PatchAll((IEnumerable)UtageHooks.All, Settings.ForceMonoModHooks); } catch (Exception ex6) { XuaLogger.AutoTranslator.Error(ex6, "An error occurred while setting up hooks for Utage."); } try { if (Settings.EnableTextMesh) { HookingHelper.PatchAll((IEnumerable)TextMeshHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex7) { XuaLogger.AutoTranslator.Error(ex7, "An error occurred while setting up hooks for TextMesh."); } try { if (Settings.EnableFairyGUI) { HookingHelper.PatchAll((IEnumerable)FairyGUIHooks.All, Settings.ForceMonoModHooks); } } catch (Exception ex8) { XuaLogger.AutoTranslator.Error(ex8, "An error occurred while setting up hooks for FairyGUI."); } } public static void InstallComponentBasedPluginTranslationHooks() { if (AutoTranslationPlugin.Current.PluginTextCaches.Count > 0 && !_installedPluginTranslationHooks) { _installedPluginTranslationHooks = true; try { HookingHelper.PatchAll((IEnumerable)PluginTranslationHooks.All, Settings.ForceMonoModHooks); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while setting up hooks for Plugin translations."); } } } public static void InstallIMGUIBasedPluginTranslationHooks(Assembly assembly, bool final) { if (!Settings.EnableIMGUI || _installedAssemblies.Contains(assembly)) { return; } if (final) { IMGUIPluginTranslationHooks.ResetHandledForAllInAssembly(assembly); } Type[] types = assembly.GetTypes(); foreach (Type type in types) { try { if (typeof(MonoBehaviour).IsAssignableFrom(type) && !type.IsAbstract) { MethodInfo method = type.GetMethod("OnGUI", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if ((object)method != null) { IMGUIPluginTranslationHooks.HookIfConfigured(method); } } } catch (Exception ex) { XuaLogger.AutoTranslator.Warn(ex, "An error occurred while hooking type: " + type.FullName); } } if (final) { _installedAssemblies.Add(assembly); } } } internal static class ImageHooks { public static readonly Type[] All = new Type[20] { typeof(MaskableGraphic_OnEnable_Hook), typeof(Image_sprite_Hook), typeof(Image_overrideSprite_Hook), typeof(Image_material_Hook), typeof(RawImage_texture_Hook), typeof(Cursor_SetCursor_Hook), typeof(Material_mainTexture_Hook), typeof(CubismRenderer_MainTexture_Hook), typeof(CubismRenderer_TryInitialize_Hook), typeof(UIAtlas_spriteMaterial_Hook), typeof(UISprite_OnInit_Hook), typeof(UISprite_material_Hook), typeof(UISprite_atlas_Hook), typeof(UI2DSprite_sprite2D_Hook), typeof(UI2DSprite_material_Hook), typeof(UITexture_mainTexture_Hook), typeof(UITexture_material_Hook), typeof(UIPanel_clipTexture_Hook), typeof(UIRect_OnInit_Hook), typeof(DicingTextures_GetTexture_Hook) }; public static readonly Type[] Sprite = new Type[1] { typeof(Sprite_texture_Hook) }; public static readonly Type[] SpriteRenderer = new Type[1] { typeof(SpriteRenderer_sprite_Hook) }; } internal static class DicingTextures_GetTexture_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.DicingTextures != null; } private static MethodBase TargetMethod(object instance) { TypeContainer dicingTextures = UnityTypes.DicingTextures; return AccessToolsShim.Method((dicingTextures != null) ? dicingTextures.ClrType : null, "GetTexture", new Type[1] { typeof(string) }); } public static void Postfix(object __instance, ref Texture2D __result) { AutoTranslationPlugin.Current.Hook_ImageChanged(ref __result, isPrefixHooked: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Texture2D MM_Detour(object __instance, string arg1) { Texture2D __result = _original(__instance, arg1); Postfix(__instance, ref __result); return __result; } } internal static class Sprite_texture_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Sprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer sprite = UnityTypes.Sprite; return AccessToolsShim.Property((sprite != null) ? sprite.ClrType : null, "texture")?.GetGetMethod(); } private static void Postfix(ref Texture2D __result) { AutoTranslationPlugin.Current.Hook_ImageChanged(ref __result, isPrefixHooked: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Texture2D MM_Detour(Sprite __instance) { Texture2D __result = _original(__instance); Postfix(ref __result); return __result; } } internal static class SpriteRenderer_sprite_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.SpriteRenderer != null; } private static MethodBase TargetMethod(object instance) { TypeContainer spriteRenderer = UnityTypes.SpriteRenderer; return AccessToolsShim.Property((spriteRenderer != null) ? spriteRenderer.ClrType : null, "sprite")?.GetSetMethod(); } public static void Prefix(SpriteRenderer __instance, ref Sprite value) { bool imageHooksEnabled = CallOrigin.ImageHooksEnabled; CallOrigin.ImageHooksEnabled = false; Texture2D texture; try { texture = value.texture; } finally { CallOrigin.ImageHooksEnabled = imageHooksEnabled; } AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref value, ref texture, isPrefixHooked: true, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(SpriteRenderer __instance, Sprite sprite) { Prefix(__instance, ref sprite); _original(__instance, sprite); } } internal static class CubismRenderer_MainTexture_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.CubismRenderer != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.CubismRenderer.ClrType, "MainTexture")?.GetSetMethod(); } public static void Prefix(Component __instance, ref Texture2D value) { AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref value, isPrefixHooked: true, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, ref Texture2D value) { Prefix(__instance, ref value); _original(__instance, value); } } internal static class CubismRenderer_TryInitialize_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.CubismRenderer != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.CubismRenderer.ClrType, "TryInitialize", new Type[0]); } public static void Prefix(Component __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: true, onEnable: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { Prefix(__instance); _original(__instance); } } internal static class Material_mainTexture_Hook { private static Action _original; private static bool Prepare(object instance) { return true; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(typeof(Material), "mainTexture")?.GetSetMethod(); } public static void Prefix(Material __instance, ref Texture value) { Texture2D texture = default(Texture2D); if (ObjectExtensions.TryCastTo((object)value, ref texture)) { AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: true, onEnable: false); value = (Texture)(object)texture; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Material __instance, ref Texture value) { Prefix(__instance, ref value); _original(__instance, value); } } internal static class MaskableGraphic_OnEnable_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.MaskableGraphic != null; } private static MethodBase TargetMethod(object instance) { TypeContainer maskableGraphic = UnityTypes.MaskableGraphic; return AccessToolsShim.Method((maskableGraphic != null) ? maskableGraphic.ClrType : null, "OnEnable", new Type[0]); } public static void Postfix(Component __instance) { Type unityType = ObjectExtensions.GetUnityType((object)__instance); if ((UnityTypes.Image != null && UnityTypes.Image.IsAssignableFrom(unityType)) || (UnityTypes.RawImage != null && UnityTypes.RawImage.IsAssignableFrom(unityType))) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: true); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { _original(__instance); Postfix(__instance); } } internal static class Image_sprite_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Image != null; } private static MethodBase TargetMethod(object instance) { TypeContainer image = UnityTypes.Image; return AccessToolsShim.Property((image != null) ? image.ClrType : null, "sprite")?.GetSetMethod(); } public static void Postfix(Component __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, Sprite value) { _original(__instance, value); Postfix(__instance); } } internal static class Image_overrideSprite_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Image != null; } private static MethodBase TargetMethod(object instance) { TypeContainer image = UnityTypes.Image; return AccessToolsShim.Property((image != null) ? image.ClrType : null, "overrideSprite")?.GetSetMethod(); } public static void Postfix(Component __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, Sprite value) { _original(__instance, value); Postfix(__instance); } } internal static class Image_material_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Image != null; } private static MethodBase TargetMethod(object instance) { TypeContainer image = UnityTypes.Image; return AccessToolsShim.Property((image != null) ? image.ClrType : null, "material")?.GetSetMethod(); } public static void Postfix(Component __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, Material value) { _original(__instance, value); Postfix(__instance); } } internal static class RawImage_texture_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.RawImage != null; } private static MethodBase TargetMethod(object instance) { TypeContainer rawImage = UnityTypes.RawImage; return AccessToolsShim.Property((rawImage != null) ? rawImage.ClrType : null, "texture")?.GetSetMethod(); } public static void Prefix(Component __instance, ref Texture value) { Texture2D texture = default(Texture2D); if (ObjectExtensions.TryCastTo((object)value, ref texture)) { AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: true, onEnable: false); value = (Texture)(object)texture; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, Texture value) { Prefix(__instance, ref value); _original(__instance, value); } } internal static class Cursor_SetCursor_Hook { private static Action _original; private static bool Prepare(object instance) { return true; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(typeof(Cursor), "SetCursor", new Type[3] { typeof(Texture2D), typeof(Vector2), typeof(CursorMode) }); } public static void Prefix(ref Texture2D texture) { AutoTranslationPlugin.Current.Hook_ImageChanged(ref texture, isPrefixHooked: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Texture2D texture, Vector2 arg2, CursorMode arg3) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Prefix(ref texture); _original(texture, arg2, arg3); } } internal static class UIAtlas_spriteMaterial_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UIAtlas != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uIAtlas = UnityTypes.UIAtlas; return AccessToolsShim.Property((uIAtlas != null) ? uIAtlas.ClrType : null, "spriteMaterial")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, Material value) { _original(__instance, value); Postfix(__instance); } } internal static class UISprite_OnInit_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UISprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uISprite = UnityTypes.UISprite; return AccessToolsShim.Method((uISprite != null) ? uISprite.ClrType : null, "OnInit", new Type[0]); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance) { _original(__instance); Postfix(__instance); } } internal static class UISprite_material_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UISprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uISprite = UnityTypes.UISprite; return AccessToolsShim.Property((uISprite != null) ? uISprite.ClrType : null, "material")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, Material value) { _original(__instance, value); Postfix(__instance); } } internal static class UISprite_atlas_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UISprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uISprite = UnityTypes.UISprite; return AccessToolsShim.Property((uISprite != null) ? uISprite.ClrType : null, "atlas")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class UITexture_mainTexture_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UITexture != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uITexture = UnityTypes.UITexture; return AccessToolsShim.Property((uITexture != null) ? uITexture.ClrType : null, "mainTexture")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class UITexture_material_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UITexture != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uITexture = UnityTypes.UITexture; return AccessToolsShim.Property((uITexture != null) ? uITexture.ClrType : null, "material")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class UIRect_OnInit_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UIRect != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uIRect = UnityTypes.UIRect; return AccessToolsShim.Method((uIRect != null) ? uIRect.ClrType : null, "OnInit", new Type[0]); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance) { _original(__instance); Postfix(__instance); } } internal static class UI2DSprite_sprite2D_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UI2DSprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uI2DSprite = UnityTypes.UI2DSprite; return AccessToolsShim.Property((uI2DSprite != null) ? uI2DSprite.ClrType : null, "sprite2D")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class UI2DSprite_material_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UI2DSprite != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uI2DSprite = UnityTypes.UI2DSprite; return AccessToolsShim.Property((uI2DSprite != null) ? uI2DSprite.ClrType : null, "material")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class UIPanel_clipTexture_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UIPanel != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.UIPanel.ClrType, "clipTexture")?.GetSetMethod(); } public static void Postfix(object __instance) { Texture2D texture = null; AutoTranslationPlugin.Current.Hook_ImageChangedOnComponent(__instance, ref texture, isPrefixHooked: false, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, object value) { _original(__instance, value); Postfix(__instance); } } internal static class IMGUIBlocker { private static HashSet HandledMethods = new HashSet(); public static void BlockIfConfigured(WindowFunction function, int windowId) { if (Settings.BlacklistedIMGUIPlugins.Count == 0) { return; } MethodInfo method = ((Delegate)(object)function).Method; if (HandledMethods.Contains(method)) { return; } HandledMethods.Add(method); try { if (IsBlackslisted(method)) { XuaLogger.AutoTranslator.Info("Attempting to hook " + method.DeclaringType.FullName.ToString() + "." + method.Name + " to disable translation in window."); IMGUIWindow_Function_Hook.Register(method); HookingHelper.PatchType(typeof(IMGUIWindow_Function_Hook), Settings.ForceMonoModHooks); IMGUIWindow_Function_Hook.Clean(); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while attempting to hook " + method.DeclaringType.FullName.ToString() + " to disable translation in window."); } } public static bool IsBlackslisted(MethodInfo method) { Type declaringType = method.DeclaringType; Assembly assembly = declaringType.Assembly; if ((object)assembly == typeof(IMGUIBlocker).Assembly) { return false; } if (!AutoTranslationPlugin.Current.IsTemporarilyDisabled() && !IsBlacklistedName(method.Name) && !IsBlacklistedName(declaringType.Name)) { return IsBlacklistedName(assembly.GetName().Name); } return true; } public static bool IsBlacklistedName(string name) { return Settings.BlacklistedIMGUIPlugins.Any((string x) => name.IndexOf(x, StringComparison.OrdinalIgnoreCase) > -1); } } internal static class IMGUIWindow_Function_Hook { private static MethodInfo _nextMethod; public static void Register(MethodInfo method) { _nextMethod = method; } public static void Clean() { _nextMethod = null; } private static bool Prepare(object instance) { return true; } private static MethodBase TargetMethod(object instance) { return _nextMethod; } private static void Prefix() { AutoTranslationPlugin.Current.DisableAutoTranslator(); } private static void Finalizer() { AutoTranslationPlugin.Current.EnableAutoTranslator(); } private static MethodInfo Get_MM_Detour() { if (_nextMethod.IsStatic) { return typeof(IMGUIWindow_Function_Hook).GetMethod("MM_Detour_Static", BindingFlags.Static | BindingFlags.NonPublic); } return typeof(IMGUIWindow_Function_Hook).GetMethod("MM_Detour_Instance", BindingFlags.Static | BindingFlags.NonPublic); } private static void MM_Detour_Instance(Action orig, object self, int id) { try { AutoTranslationPlugin.Current.DisableAutoTranslator(); orig(self, id); } finally { AutoTranslationPlugin.Current.EnableAutoTranslator(); } } private static void MM_Detour_Static(Action orig, int id) { try { AutoTranslationPlugin.Current.DisableAutoTranslator(); orig(id); } finally { AutoTranslationPlugin.Current.EnableAutoTranslator(); } } } internal static class IMGUIHooks { public static readonly Type[][] All = new Type[9][] { new Type[2] { typeof(GUI_BeginGroup_Hook_New), typeof(GUI_BeginGroup_Hook) }, new Type[2] { typeof(GUI_DoLabel_Hook_New), typeof(GUI_DoLabel_Hook) }, new Type[2] { typeof(GUI_DoButton_Hook_New), typeof(GUI_DoButton_Hook) }, new Type[3] { typeof(GUI_DoButtonGrid_Hook_2019), typeof(GUI_DoButtonGrid_Hook_2018), typeof(GUI_DoButtonGrid_Hook) }, new Type[2] { typeof(GUI_DoToggle_Hook_New), typeof(GUI_DoToggle_Hook) }, new Type[1] { typeof(GUI_Box_Hook) }, new Type[1] { typeof(GUI_DoRepeatButton_Hook) }, new Type[1] { typeof(GUI_DoModalWindow_Hook) }, new Type[1] { typeof(GUI_DoWindow_Hook) } }; } [HookingHelperPriority(0)] internal static class GUI_BeginGroup_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "BeginGroup", new Type[3] { typeof(Rect), typeof(GUIContent), typeof(GUIStyle) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Rect arg1, GUIContent arg2, GUIStyle arg3) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); _original(arg1, arg2, arg3); } } [HookingHelperPriority(0)] internal static class GUI_BeginGroup_Hook_New { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "BeginGroup", new Type[4] { typeof(Rect), typeof(GUIContent), typeof(GUIStyle), typeof(Vector2) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Rect arg1, GUIContent arg2, GUIStyle arg3, Vector2 arg4) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); _original(arg1, arg2, arg3, arg4); } } [HookingHelperPriority(0)] internal static class GUI_Box_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "Box", new Type[3] { typeof(Rect), typeof(GUIContent), typeof(GUIStyle) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Rect arg1, GUIContent arg2, GUIStyle arg3) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); _original(arg1, arg2, arg3); } } [HookingHelperPriority(0)] internal static class GUI_DoRepeatButton_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoRepeatButton", new Type[4] { typeof(Rect), typeof(GUIContent), typeof(GUIStyle), typeof(FocusType) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static bool MM_Detour(Rect arg1, GUIContent arg2, GUIStyle arg3, FocusType arg4) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); return _original(arg1, arg2, arg3, arg4); } } [HookingHelperPriority(0)] internal static class GUI_DoLabel_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoLabel", new Type[3] { typeof(Rect), typeof(GUIContent), typeof(IntPtr) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Rect arg1, GUIContent arg2, IntPtr arg3) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); _original(arg1, arg2, arg3); } } [HookingHelperPriority(0)] internal static class GUI_DoLabel_Hook_New { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoLabel", new Type[3] { typeof(Rect), typeof(GUIContent), typeof(GUIStyle) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Rect arg1, GUIContent arg2, GUIStyle arg3) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); _original(arg1, arg2, arg3); } } [HookingHelperPriority(0)] internal static class GUI_DoButton_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoButton", new Type[3] { typeof(Rect), typeof(GUIContent), typeof(IntPtr) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static bool MM_Detour(Rect arg1, GUIContent arg2, IntPtr arg3) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg2); return _original(arg1, arg2, arg3); } } [HookingHelperPriority(0)] internal static class GUI_DoButton_Hook_New { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoButton", new Type[4] { typeof(Rect), typeof(int), typeof(GUIContent), typeof(GUIStyle) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static bool MM_Detour(Rect arg1, int arg2, GUIContent arg3, GUIStyle arg4) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg3); return _original(arg1, arg2, arg3, arg4); } } [HookingHelperPriority(0)] internal static class GUI_DoModalWindow_Hook { private delegate Rect OriginalMethod(int arg1, Rect arg2, WindowFunction arg3, GUIContent arg4, GUIStyle arg5, GUISkin arg6); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoModalWindow", new Type[6] { typeof(int), typeof(Rect), typeof(WindowFunction), typeof(GUIContent), typeof(GUIStyle), typeof(GUISkin) }); } private static void Prefix(int id, WindowFunction func, GUIContent content) { IMGUIBlocker.BlockIfConfigured(func, id); IMGUIPluginTranslationHooks.HookIfConfigured(func); AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Rect MM_Detour(int arg1, Rect arg2, WindowFunction arg3, GUIContent arg4, GUIStyle arg5, GUISkin arg6) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) Prefix(arg1, arg3, arg4); return _original(arg1, arg2, arg3, arg4, arg5, arg6); } } [HookingHelperPriority(0)] internal static class GUI_DoWindow_Hook { private delegate Rect OriginalMethod(int arg1, Rect arg2, WindowFunction arg3, GUIContent arg4, GUIStyle arg5, GUISkin arg6, bool arg7); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoWindow", new Type[7] { typeof(int), typeof(Rect), typeof(WindowFunction), typeof(GUIContent), typeof(GUIStyle), typeof(GUISkin), typeof(bool) }); } private static void Prefix(int id, WindowFunction func, GUIContent title) { IMGUIBlocker.BlockIfConfigured(func, id); IMGUIPluginTranslationHooks.HookIfConfigured(func); AutoTranslationPlugin.Current.Hook_TextChanged(title, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static Rect MM_Detour(int arg1, Rect arg2, WindowFunction arg3, GUIContent arg4, GUIStyle arg5, GUISkin arg6, bool arg7) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) Prefix(arg1, arg3, arg4); return _original(arg1, arg2, arg3, arg4, arg5, arg6, arg7); } } [HookingHelperPriority(0)] internal static class GUI_DoButtonGrid_Hook { private delegate int OriginalMethod(Rect arg1, int arg2, GUIContent[] arg3, int arg4, GUIStyle arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoButtonGrid", new Type[8] { typeof(Rect), typeof(int), typeof(GUIContent[]), typeof(int), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle) }); } private static void Prefix(GUIContent[] contents) { foreach (GUIContent ui in contents) { AutoTranslationPlugin.Current.Hook_TextChanged(ui, onEnable: false); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static int MM_Detour(Rect arg1, int arg2, GUIContent[] arg3, int arg4, GUIStyle arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg3); return _original(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); } } [HookingHelperPriority(0)] internal static class GUI_DoButtonGrid_Hook_2018 { private delegate int OriginalMethod(Rect arg1, int arg2, GUIContent[] arg3, string[] arg4, int arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8, GUIStyle arg9, int arg10); private static OriginalMethod _original; private static bool Prepare(object instance) { if (UnityTypes.GUI != null) { return UnityTypes.GUI_ToolbarButtonSize != null; } return false; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoButtonGrid", new Type[10] { typeof(Rect), typeof(int), typeof(GUIContent[]), typeof(string[]), typeof(int), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle), UnityTypes.GUI_ToolbarButtonSize.ClrType }); } private static void Prefix(GUIContent[] contents) { foreach (GUIContent ui in contents) { AutoTranslationPlugin.Current.Hook_TextChanged(ui, onEnable: false); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static int MM_Detour(Rect arg1, int arg2, GUIContent[] arg3, string[] arg4, int arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8, GUIStyle arg9, int arg10) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg3); return _original(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10); } } [HookingHelperPriority(0)] internal static class GUI_DoButtonGrid_Hook_2019 { private delegate int OriginalMethod(Rect arg1, int arg2, GUIContent[] arg3, string[] arg4, int arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8, GUIStyle arg9, int arg10, bool[] arg11); private static OriginalMethod _original; private static bool Prepare(object instance) { if (UnityTypes.GUI != null) { return UnityTypes.GUI_ToolbarButtonSize != null; } return false; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoButtonGrid", new Type[11] { typeof(Rect), typeof(int), typeof(GUIContent[]), typeof(string[]), typeof(int), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle), typeof(GUIStyle), UnityTypes.GUI_ToolbarButtonSize.ClrType, typeof(bool[]) }); } private static void Prefix(GUIContent[] contents) { foreach (GUIContent ui in contents) { AutoTranslationPlugin.Current.Hook_TextChanged(ui, onEnable: false); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static int MM_Detour(Rect arg1, int arg2, GUIContent[] arg3, string[] arg4, int arg5, GUIStyle arg6, GUIStyle arg7, GUIStyle arg8, GUIStyle arg9, int arg10, bool[] arg11) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg3); return _original(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11); } } [HookingHelperPriority(0)] internal static class GUI_DoToggle_Hook { private delegate bool OriginalMethod(Rect arg1, int arg2, bool arg3, GUIContent arg4, IntPtr arg5); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoToggle", new Type[5] { typeof(Rect), typeof(int), typeof(bool), typeof(GUIContent), typeof(IntPtr) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static bool MM_Detour(Rect arg1, int arg2, bool arg3, GUIContent arg4, IntPtr arg5) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg4); return _original(arg1, arg2, arg3, arg4, arg5); } } [HookingHelperPriority(0)] internal static class GUI_DoToggle_Hook_New { private delegate bool OriginalMethod(Rect arg1, int arg2, bool arg3, GUIContent arg4, GUIStyle arg5); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.GUI != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GUI.ClrType, "DoToggle", new Type[5] { typeof(Rect), typeof(int), typeof(bool), typeof(GUIContent), typeof(GUIStyle) }); } private static void Prefix(GUIContent content) { AutoTranslationPlugin.Current.Hook_TextChanged(content, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static bool MM_Detour(Rect arg1, int arg2, bool arg3, GUIContent arg4, GUIStyle arg5) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Prefix(arg4); return _original(arg1, arg2, arg3, arg4, arg5); } } internal static class IMGUIPluginTranslationHooks { private static HashSet HandledMethods = new HashSet(); private static HashSet HookedMethods = new HashSet(); public static void HookIfConfigured(WindowFunction function) { if (AutoTranslationPlugin.Current.PluginTextCaches.Count != 0) { HookIfConfigured(((Delegate)(object)function).Method); } } public static void ResetHandledForAllInAssembly(Assembly assembly) { HandledMethods.RemoveWhere((MethodInfo x) => x.DeclaringType.Assembly.Equals(assembly)); } public static void HookIfConfigured(MethodInfo method) { if (HandledMethods.Contains(method)) { return; } HandledMethods.Add(method); if (HookedMethods.Contains(method)) { return; } string text = method.DeclaringType.FullName.ToString() + "." + method.Name; try { Assembly assembly = method.DeclaringType.Assembly; if (AutoTranslationPlugin.Current.PluginTextCaches.TryGetValue(assembly.GetName().Name, out var value)) { XuaLogger.AutoTranslator.Info("Attempting to hook " + text + " to enable plugin specific translations."); Type type = method.DeclaringType.Assembly.GetTypes().FirstOrDefault((Type x) => typeof(MonoBehaviour).IsAssignableFrom(x)); if ((object)type == null) { XuaLogger.AutoTranslator.Warn("Could not find any MonoBehaviours in assembly owning method the method: " + text); return; } Type type2 = type.GetType(); CompositeTextTranslationCache orCreateCompositeCache = AutoTranslationPlugin.Current.TextCache.GetOrCreateCompositeCache(value); Type type3 = typeof(PluginCallbacks_Function_Hook<>).MakeGenericType(type2); type3.GetMethod("Register", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(null, new object[1] { method }); type3.GetMethod("SetTextCache", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(null, new object[1] { orCreateCompositeCache }); HookingHelper.PatchType(type3, Settings.ForceMonoModHooks); HookedMethods.Add(method); type3.GetMethod("Clean", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).Invoke(null, null); } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while attempting to hook " + text + " to disable translation in window."); } } } internal static class PluginCallbacks_Function_Hook { private static MethodInfo _nextMethod; private static IReadOnlyTextTranslationCache _cache; public static void SetTextCache(IReadOnlyTextTranslationCache cache) { _cache = cache; } public static void Register(MethodInfo method) { _nextMethod = method; } public static void Clean() { _nextMethod = null; } private static bool Prepare(object instance) { return true; } private static MethodBase TargetMethod(object instance) { return _nextMethod; } private static void Prefix() { CallOrigin.TextCache = _cache; } private static void Finalizer() { CallOrigin.TextCache = null; } } internal static class PluginTranslationHooks { public static readonly Type[] All = new Type[6] { typeof(Transform_SetParent_Hook), typeof(GameObject_AddComponent_Hook), typeof(Object_InstantiateSingle_Hook), typeof(Object_InstantiateSingleWithParent_Hook), typeof(Object_CloneSingle_Hook), typeof(Object_CloneSingleWithParent_Hook) }; } internal static class Transform_SetParent_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Transform != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.Transform.ClrType, "SetParent", new Type[2] { UnityTypes.Transform.ClrType, typeof(bool) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Transform __instance, Transform parent, bool worldPositionStays) { if ((Object)(object)parent != (Object)null) { TransformInfo extensionData = ExtensionDataHelper.GetExtensionData((object)parent); if (extensionData?.TextCache != null) { IReadOnlyTextTranslationCache textCache = CallOrigin.TextCache; CallOrigin.TextCache = extensionData.TextCache; try { CallOrigin.AssociateSubHierarchyWithTransformInfo(__instance, extensionData); } finally { CallOrigin.TextCache = textCache; } } } _original(__instance, parent, worldPositionStays); } } internal static class GameObject_AddComponent_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.GameObject != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GameObject.ClrType, "Internal_AddComponentWithType", new Type[1] { typeof(Type) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Component MM_Detour(GameObject __instance, Type componentType) { Component val = _original(__instance, componentType); if (val.IsKnownTextType()) { IReadOnlyTextTranslationCache readOnlyTextTranslationCache = CallOrigin.CalculateTextCacheFromStackTrace(null); if (readOnlyTextTranslationCache != null) { val.GetOrCreateTextTranslationInfo().TextCache = readOnlyTextTranslationCache; } } return val; } } internal static class Object_InstantiateSingle_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Object != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.Object.ClrType, "Internal_InstantiateSingle", new Type[3] { typeof(Object), typeof(Vector3), typeof(Quaternion) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Object MM_Detour(Object data, Vector3 pos, Quaternion rot) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) IReadOnlyTextTranslationCache textCache = CallOrigin.TextCache; try { CallOrigin.TextCache = CallOrigin.CalculateTextCacheFromStackTrace(null); Object val = _original(data, pos, rot); if (CallOrigin.TextCache != null) { GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null); if (val2 != null && !val2.activeInHierarchy) { val2.SetTextCacheForAllObjectsInHierachy(CallOrigin.TextCache); } } return val; } finally { CallOrigin.TextCache = textCache; } } } internal static class Object_InstantiateSingleWithParent_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Object != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.Object.ClrType, "Internal_InstantiateSingleWithParent", new Type[4] { typeof(Object), typeof(Transform), typeof(Vector3), typeof(Quaternion) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Object MM_Detour(Object data, Transform parent, Vector3 pos, Quaternion rot) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) IReadOnlyTextTranslationCache textCache = CallOrigin.TextCache; try { CallOrigin.TextCache = CallOrigin.CalculateTextCacheFromStackTrace((parent != null) ? ((Component)parent).gameObject : null); Object val = _original(data, parent, pos, rot); if (CallOrigin.TextCache != null) { GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null); if (val2 != null && !val2.activeInHierarchy) { val2.SetTextCacheForAllObjectsInHierachy(CallOrigin.TextCache); } } return val; } finally { CallOrigin.TextCache = textCache; } } } internal static class Object_CloneSingle_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Object != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.Object.ClrType, "Internal_CloneSingle", new Type[1] { typeof(Object) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Object MM_Detour(Object data) { IReadOnlyTextTranslationCache textCache = CallOrigin.TextCache; try { CallOrigin.TextCache = CallOrigin.CalculateTextCacheFromStackTrace(null); Object val = _original(data); if (CallOrigin.TextCache != null) { GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null); if (val2 != null && !val2.activeInHierarchy) { val2.SetTextCacheForAllObjectsInHierachy(CallOrigin.TextCache); } } return val; } finally { CallOrigin.TextCache = textCache; } } } internal static class Object_CloneSingleWithParent_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Object != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.Object.ClrType, "Internal_CloneSingleWithParent", new Type[3] { typeof(Object), typeof(Transform), typeof(bool) }); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static Object MM_Detour(Object data, Transform parent, bool worldPositionStays) { IReadOnlyTextTranslationCache textCache = CallOrigin.TextCache; try { CallOrigin.TextCache = CallOrigin.CalculateTextCacheFromStackTrace((parent != null) ? ((Component)parent).gameObject : null); Object val = _original(data, parent, worldPositionStays); if (CallOrigin.TextCache != null) { GameObject val2 = (GameObject)(object)((val is GameObject) ? val : null); if (val2 != null && !val2.activeInHierarchy) { val2.SetTextCacheForAllObjectsInHierachy(CallOrigin.TextCache); } } return val; } finally { CallOrigin.TextCache = textCache; } } } internal static class TextGetterCompatHooks { public static readonly Type[] All = new Type[3] { typeof(Text_text_Hook), typeof(TMP_Text_text_Hook), typeof(NGUI_Text_text_Hook) }; } internal static class Text_text_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.Text != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.Text.ClrType, "text")?.GetGetMethod(); } private static void Postfix(object __instance, ref string __result) { TextGetterCompatModeHelper.ReplaceTextWithOriginal(__instance, ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static string MM_Detour(object __instance) { string __result = _original(__instance); Postfix(__instance, ref __result); return __result; } } internal static class TMP_Text_text_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.TMP_Text.ClrType, "text")?.GetGetMethod(); } private static void Postfix(object __instance, ref string __result) { TextGetterCompatModeHelper.ReplaceTextWithOriginal(__instance, ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static string MM_Detour(object __instance) { string __result = _original(__instance); Postfix(__instance, ref __result); return __result; } } internal static class NGUI_Text_text_Hook { private static Func _original; private static bool Prepare(object instance) { return UnityTypes.UILabel != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.UILabel.ClrType, "text")?.GetGetMethod(); } private static void Postfix(object __instance, ref string __result) { TextGetterCompatModeHelper.ReplaceTextWithOriginal(__instance, ref __result); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static string MM_Detour(object __instance) { string __result = _original(__instance); Postfix(__instance, ref __result); return __result; } } internal static class TextAssetHooks { public static readonly Type[] All = new Type[2] { typeof(TextAsset_bytes_Hook), typeof(TextAsset_text_Hook) }; } internal static class TextAsset_bytes_Hook { private delegate byte[] OriginalMethod(TextAsset __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.TextAsset != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textAsset = UnityTypes.TextAsset; return AccessToolsShim.Property((textAsset != null) ? textAsset.ClrType : null, "bytes")?.GetGetMethod(); } private static void Postfix(TextAsset __instance, ref byte[] __result) { if (__result != null) { TextAssetExtensionData extensionData = ExtensionDataHelper.GetExtensionData((object)__instance); if (extensionData != null) { __result = extensionData.Data; } } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static byte[] MM_Detour(TextAsset __instance) { byte[] __result = _original(__instance); Postfix(__instance, ref __result); return __result; } } internal static class TextAsset_text_Hook { private delegate string OriginalMethod(TextAsset __instance); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.TextAsset != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textAsset = UnityTypes.TextAsset; return AccessToolsShim.Property((textAsset != null) ? textAsset.ClrType : null, "text")?.GetGetMethod(); } private static void Postfix(TextAsset __instance, ref string __result) { if (__result != null) { TextAssetExtensionData extensionData = ExtensionDataHelper.GetExtensionData((object)__instance); if (extensionData != null) { __result = extensionData.Text; } } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static string MM_Detour(TextAsset __instance) { string __result = _original(__instance); Postfix(__instance, ref __result); return __result; } } internal static class UtageHooks { public static readonly Type[] All = new Type[5] { typeof(AdvEngine_JumpScenario_Hook), typeof(UguiNovelTextGenerator_LengthOfView_Hook), typeof(TextArea2D_text_Hook), typeof(TextArea2D_TextData_Hook), typeof(TextData_ctor_Hook) }; } internal static class AdvEngine_JumpScenario_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.AdvEngine != null; } private static MethodBase TargetMethod(object instance) { TypeContainer advEngine = UnityTypes.AdvEngine; return AccessToolsShim.Method((advEngine != null) ? advEngine.ClrType : null, "JumpScenario", new Type[1] { typeof(string) }); } private static void Prefix(ref string label) { UtageHelper.FixLabel(ref label); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { Prefix(ref value); _original(__instance, value); } } internal static class UguiNovelTextGenerator_LengthOfView_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UguiNovelTextGenerator != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uguiNovelTextGenerator = UnityTypes.UguiNovelTextGenerator; return AccessToolsShim.Property((uguiNovelTextGenerator != null) ? uguiNovelTextGenerator.ClrType : null, "LengthOfView").GetSetMethod(nonPublic: true); } private static void Prefix(ref int value) { value = -1; } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, int value) { Prefix(ref value); _original(__instance, value); } } [HookingHelperPriority(0)] internal static class TextArea2D_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextArea2D != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textArea2D = UnityTypes.TextArea2D; return AccessToolsShim.Property((textArea2D != null) ? textArea2D.ClrType : null, "text")?.GetSetMethod(); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TextArea2D_TextData_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextArea2D != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.TextArea2D.ClrType, "TextData")?.GetSetMethod(); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, object value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TextData_ctor_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextData != null; } private static MethodBase TargetMethod(object instance) { return UnityTypes.TextData.ClrType.GetConstructor(new Type[1] { typeof(string) }); } private static void Postfix(object __instance, string text) { ExtensionDataHelper.SetExtensionData(__instance, text); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string text) { _original(__instance, text); Postfix(__instance, text); } } } namespace XUnity.AutoTranslator.Plugin.Core.Hooks.UIElements { internal static class UIElementsHooks { public static readonly Type[] All = new Type[1] { typeof(TextElement_text_Hook) }; } [HookingHelperPriority(0)] internal static class TextElement_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextElement != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textElement = UnityTypes.TextElement; return AccessToolsShim.Property((textElement != null) ? textElement.ClrType : null, "text")?.GetSetMethod(); } private static void Postfix(object __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } } namespace XUnity.AutoTranslator.Plugin.Core.Hooks.TextMeshPro { internal static class TextMeshProHooks { public static readonly Type[] All = new Type[12] { typeof(TeshMeshProUGUI_OnEnable_Hook), typeof(TeshMeshPro_OnEnable_Hook), typeof(TMP_Text_text_Hook), typeof(TMP_Text_SetText_Hook1), typeof(TMP_Text_SetText_Hook2), typeof(TMP_Text_SetText_Hook3), typeof(TMP_Text_SetCharArray_Hook1), typeof(TMP_Text_SetCharArray_Hook2), typeof(TMP_Text_SetCharArray_Hook3), typeof(TextWindow_SetText_Hook), typeof(TeshMeshProUGUI_text_Hook), typeof(TeshMeshPro_text_Hook) }; public static readonly Type[] DisableScrollInTmp = new Type[1] { typeof(TMP_Text_maxVisibleCharacters_Hook) }; } [HookingHelperPriority(0)] internal static class TextWindow_SetText_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextWindow != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.TextWindow.ClrType, "SetText", new Type[1] { typeof(string) }); } private static void Postfix(object __instance) { Settings.SetCurText?.Invoke(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TeshMeshProUGUI_text_Hook { private static Action _original; private static bool Prepare(object instance) { if (UnityTypes.TMP_Text == null) { return UnityTypes.TextMeshProUGUI != null; } return false; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.TextMeshProUGUI.ClrType, "text").GetSetMethod(); } private static void Postfix(object __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TeshMeshPro_text_Hook { private static Action _original; private static bool Prepare(object instance) { if (UnityTypes.TMP_Text == null) { return UnityTypes.TextMeshPro != null; } return false; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(UnityTypes.TextMeshPro.ClrType, "text").GetSetMethod(); } private static void Postfix(object __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(object __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetText_Hook1 { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Method((tMP_Text != null) ? tMP_Text.ClrType : null, "SetText", new Type[1] { typeof(StringBuilder) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, StringBuilder value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetText_Hook2 { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Method((tMP_Text != null) ? tMP_Text.ClrType : null, "SetText", new Type[2] { typeof(string), typeof(bool) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value, bool arg2) { _original(__instance, value, arg2); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetText_Hook3 { private delegate void OriginalMethod(Component arg1, string arg2, float arg3, float arg4, float arg5); private static OriginalMethod _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.TMP_Text.ClrType, "SetText", new Type[4] { typeof(string), typeof(float), typeof(float), typeof(float) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx(detour); } private static void MM_Detour(Component __instance, string value, float arg2, float arg3, float arg4) { _original(__instance, value, arg2, arg3, arg4); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetCharArray_Hook1 { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Method((tMP_Text != null) ? tMP_Text.ClrType : null, "SetCharArray", new Type[1] { typeof(char[]) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, char[] value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetCharArray_Hook2 { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Method((tMP_Text != null) ? tMP_Text.ClrType : null, "SetCharArray", new Type[3] { typeof(char[]), typeof(int), typeof(int) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, char[] value, int arg2, int arg3) { _original(__instance, value, arg2, arg3); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_SetCharArray_Hook3 { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Method((tMP_Text != null) ? tMP_Text.ClrType : null, "SetCharArray", new Type[3] { typeof(int[]), typeof(int), typeof(int) }); } private static void Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, int[] value, int arg2, int arg3) { _original(__instance, value, arg2, arg3); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TeshMeshProUGUI_OnEnable_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextMeshProUGUI != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textMeshProUGUI = UnityTypes.TextMeshProUGUI; return AccessToolsShim.Method((textMeshProUGUI != null) ? textMeshProUGUI.ClrType : null, "OnEnable", new Type[0]); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { _original(__instance); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TeshMeshPro_OnEnable_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextMeshPro != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textMeshPro = UnityTypes.TextMeshPro; return AccessToolsShim.Method((textMeshPro != null) ? textMeshPro.ClrType : null, "OnEnable", new Type[0]); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { _original(__instance); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Property((tMP_Text != null) ? tMP_Text.ClrType : null, "text")?.GetSetMethod(); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class TMP_Text_maxVisibleCharacters_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TMP_Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer tMP_Text = UnityTypes.TMP_Text; return AccessToolsShim.Property((tMP_Text != null) ? tMP_Text.ClrType : null, "maxVisibleCharacters")?.GetSetMethod(); } private static void Prefix(Component __instance, ref int value) { TextTranslationInfo textTranslationInfo = __instance.GetTextTranslationInfo(); if (textTranslationInfo != null && textTranslationInfo.IsTranslated && 0 < value) { value = 99999; } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, int value) { Prefix(__instance, ref value); _original(__instance, value); } } } namespace XUnity.AutoTranslator.Plugin.Core.Hooks.UGUI { internal static class TextMeshHooks { public static readonly Type[] All = new Type[3] { typeof(TextMesh_text_Hook), typeof(GameObject_SetActive_Hook), typeof(GameObject_active_Hook) }; } [HookingHelperPriority(0)] internal static class GameObject_active_Hook { private static Action _original; private static bool Prepare(object instance) { return true; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Property(typeof(GameObject), "active")?.GetSetMethod(); } private static void Postfix(GameObject __instance, bool value) { if (value) { Component[] componentsInChildren = __instance.GetComponentsInChildren(UnityTypes.TextMesh.UnityType); foreach (Component ui in componentsInChildren) { AutoTranslationPlugin.Current.Hook_TextChanged(ui, onEnable: true); } } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(GameObject __instance, bool value) { _original(__instance, value); Postfix(__instance, value); } } [HookingHelperPriority(0)] internal static class TextMesh_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.TextMesh != null; } private static MethodBase TargetMethod(object instance) { TypeContainer textMesh = UnityTypes.TextMesh; return AccessToolsShim.Property((textMesh != null) ? textMesh.ClrType : null, "text")?.GetSetMethod(); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class GameObject_SetActive_Hook { private static Action _original; private static bool Prepare(object instance) { if (UnityTypes.GameObject != null) { return UnityTypes.TextMesh != null; } return false; } private static MethodBase TargetMethod(object instance) { return AccessToolsShim.Method(UnityTypes.GameObject.ClrType, "SetActive", new Type[1] { typeof(bool) }); } private static void _Postfix(GameObject __instance, bool value) { if (value) { Component[] componentsInChildren = __instance.GetComponentsInChildren(UnityTypes.TextMesh.UnityType); foreach (Component ui in componentsInChildren) { AutoTranslationPlugin.Current.Hook_TextChanged(ui, onEnable: true); } } } private static void Postfix(GameObject __instance, bool value) { _Postfix(__instance, value); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(GameObject __instance, bool value) { _original(__instance, value); Postfix(__instance, value); } } internal static class UGUIHooks { public static readonly Type[] All = new Type[2] { typeof(Text_text_Hook), typeof(Text_OnEnable_Hook) }; } [HookingHelperPriority(0)] internal static class Text_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer text = UnityTypes.Text; return AccessToolsShim.Property((text != null) ? text.ClrType : null, "text")?.GetSetMethod(); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class Text_OnEnable_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.Text != null; } private static MethodBase TargetMethod(object instance) { TypeContainer text = UnityTypes.Text; return AccessToolsShim.Method((text != null) ? text.ClrType : null, "OnEnable", new Type[0]); } private static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void Postfix(Component __instance) { if (UnityTypes.Text.IsAssignableFrom(ObjectExtensions.GetUnityType((object)__instance))) { _Postfix(__instance); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { _original(__instance); Postfix(__instance); } } } namespace XUnity.AutoTranslator.Plugin.Core.Hooks.NGUI { internal static class NGUIHooks { public static readonly Type[] All = new Type[2] { typeof(UILabel_text_Hook), typeof(UILabel_OnEnable_Hook) }; } [HookingHelperPriority(0)] internal static class UILabel_text_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UILabel != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uILabel = UnityTypes.UILabel; return AccessToolsShim.Property((uILabel != null) ? uILabel.ClrType : null, "text")?.GetSetMethod(); } public static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: false); } private static void Postfix(Component __instance) { _Postfix(__instance); } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance, string value) { _original(__instance, value); Postfix(__instance); } } [HookingHelperPriority(0)] internal static class UILabel_OnEnable_Hook { private static Action _original; private static bool Prepare(object instance) { return UnityTypes.UIRect != null; } private static MethodBase TargetMethod(object instance) { TypeContainer uIRect = UnityTypes.UIRect; return AccessToolsShim.Method((uIRect != null) ? uIRect.ClrType : null, "OnEnable", new Type[0]); } public static void _Postfix(Component __instance) { AutoTranslationPlugin.Current.Hook_TextChanged(__instance, onEnable: true); } private static void Postfix(Component __instance) { __instance = __instance.GetOrCreateNGUIDerivedProxy(); if ((Object)(object)__instance != (Object)null) { _Postfix(__instance); } } private static void MM_Init(object detour) { _original = DetourExtensions.GenerateTrampolineEx>(detour); } private static void MM_Detour(Component __instance) { _original(__instance); Postfix(__instance); } } } namespace XUnity.AutoTranslator.Plugin.Core.Fonts { internal static class FontCache { private static readonly Dictionary CachedFonts = new Dictionary(); private static bool _hasReadOverrideFontTextMeshPro = false; private static Object OverrideFontTextMeshPro; private static bool _hasReadFallbackFontTextMeshPro = false; private static Object FallbackFontTextMeshPro; public static Font GetOrCreate(int size) { if (!CachedFonts.TryGetValue(size, out var value)) { value = FontHelper.GetTextFont(size); CachedFonts.Add(size, value); } return value; } public static object GetOrCreateOverrideFontTextMeshPro() { if (!_hasReadOverrideFontTextMeshPro) { try { _hasReadOverrideFontTextMeshPro = true; OverrideFontTextMeshPro = FontHelper.GetTextMeshProFont(Settings.OverrideFontTextMeshPro); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading text mesh pro override font: " + Settings.OverrideFontTextMeshPro); } } return OverrideFontTextMeshPro; } public static Object GetOrCreateFallbackFontTextMeshPro() { if (!_hasReadFallbackFontTextMeshPro) { try { _hasReadFallbackFontTextMeshPro = true; FallbackFontTextMeshPro = FontHelper.GetTextMeshProFont(Settings.FallbackFontTextMeshPro); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading text mesh pro fallback font: " + Settings.FallbackFontTextMeshPro); } } return FallbackFontTextMeshPro; } } internal static class FontHelper { public static Object GetTextMeshProFont(string assetBundle) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown Object val = null; string text = Path.Combine(Paths.GameRoot, assetBundle); if (File.Exists(text)) { XuaLogger.AutoTranslator.Info("Attempting to load TextMesh Pro font from asset bundle."); AssetBundle val2 = null; if (AssetBundle_Methods.LoadFromFile != null) { val2 = (AssetBundle)AssetBundle_Methods.LoadFromFile.Invoke((object)null, new object[1] { text }); } else { if (AssetBundle_Methods.CreateFromFile == null) { XuaLogger.AutoTranslator.Error("Could not find an appropriate asset bundle load method while loading font: " + text); return null; } val2 = (AssetBundle)AssetBundle_Methods.CreateFromFile.Invoke((object)null, new object[1] { text }); } if ((Object)(object)val2 == (Object)null) { XuaLogger.AutoTranslator.Warn("Could not load asset bundle while loading font: " + text); return null; } if (UnityTypes.TMP_FontAsset != null) { if (AssetBundle_Methods.LoadAllAssets != null) { val = ((Object[])AssetBundle_Methods.LoadAllAssets.Invoke((object)val2, new object[1] { UnityTypes.TMP_FontAsset.UnityType }))?.FirstOrDefault(); } else if (AssetBundle_Methods.LoadAll != null) { val = ((Object[])AssetBundle_Methods.LoadAll.Invoke((object)val2, new object[1] { UnityTypes.TMP_FontAsset.UnityType }))?.FirstOrDefault(); } } } else { XuaLogger.AutoTranslator.Info("Attempting to load TextMesh Pro font from internal Resources API."); val = Resources.Load(assetBundle); } if (val != (Object)null) { CachedProperty version = TMP_FontAsset_Properties.Version; string text2 = ((string)((version != null) ? version.Get((object)val) : null)) ?? "Unknown"; XuaLogger.AutoTranslator.Info("Loaded TextMesh Pro font uses version: " + text2); if (version != null && Settings.TextMeshProVersion != null && text2 != Settings.TextMeshProVersion) { XuaLogger.AutoTranslator.Warn("TextMesh Pro version mismatch. Font asset version: " + text2 + ", TextMesh Pro version: " + Settings.TextMeshProVersion); } Object.DontDestroyOnLoad(val); } else { XuaLogger.AutoTranslator.Error("Could not find the TextMeshPro font asset: " + assetBundle); } return val; } public static Font GetTextFont(int size) { Font obj = Font.CreateDynamicFontFromOSFont(Settings.OverrideFont, size); Object.DontDestroyOnLoad((Object)(object)obj); return obj; } public static string[] GetOSInstalledFontNames() { return Font.GetOSInstalledFontNames(); } } } namespace XUnity.AutoTranslator.Plugin.Core.Extensions { internal static class ComponentExtensions { private interface IPropertyMover { void MoveProperty(object source, object destination); } private class PropertyMover : IPropertyMover { private readonly Func _get; private readonly Action _set; public PropertyMover(PropertyInfo propertyInfo) { MethodInfo getMethod = propertyInfo.GetGetMethod(); MethodInfo setMethod = propertyInfo.GetSetMethod(); _get = (Func)ExpressionHelper.CreateTypedFastInvoke((MethodBase)getMethod); _set = (Action)ExpressionHelper.CreateTypedFastInvoke((MethodBase)setMethod); } public void MoveProperty(object source, object destination) { TPropertyType arg = _get((T)source); _set((T)destination, arg); } } [CompilerGenerated] private sealed class d__43 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private Component <>2__current; private int <>l__initialThreadId; private GameObject go; public GameObject <>3__go; private Component[] <>7__wrap1; private int <>7__wrap2; Component IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__43(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (Settings.EnableTextMeshPro && UnityTypes.TMP_Text != null) { <>7__wrap1 = go.GetComponentsInChildren(UnityTypes.TMP_Text.UnityType, true); <>7__wrap2 = 0; goto IL_0090; } goto IL_00a7; case 1: <>1__state = -1; <>7__wrap2++; goto IL_0090; case 2: <>1__state = -1; <>7__wrap2++; goto IL_010d; case 3: <>1__state = -1; <>7__wrap2++; goto IL_018a; case 4: { <>1__state = -1; <>7__wrap2++; goto IL_0209; } IL_010d: if (<>7__wrap2 < <>7__wrap1.Length) { Component val = <>7__wrap1[<>7__wrap2]; <>2__current = val; <>1__state = 2; return true; } <>7__wrap1 = null; goto IL_0124; IL_018a: if (<>7__wrap2 < <>7__wrap1.Length) { Component val2 = <>7__wrap1[<>7__wrap2]; <>2__current = val2; <>1__state = 3; return true; } <>7__wrap1 = null; goto IL_01a1; IL_0090: if (<>7__wrap2 < <>7__wrap1.Length) { Component val3 = <>7__wrap1[<>7__wrap2]; <>2__current = val3; <>1__state = 1; return true; } <>7__wrap1 = null; goto IL_00a7; IL_0209: if (<>7__wrap2 < <>7__wrap1.Length) { Component val4 = <>7__wrap1[<>7__wrap2]; <>2__current = val4; <>1__state = 4; return true; } <>7__wrap1 = null; break; IL_0124: if (Settings.EnableTextMesh && UnityTypes.TextMesh != null) { <>7__wrap1 = go.GetComponentsInChildren(UnityTypes.TextMesh.UnityType, true); <>7__wrap2 = 0; goto IL_018a; } goto IL_01a1; IL_00a7: if (Settings.EnableUGUI && UnityTypes.Text != null) { <>7__wrap1 = go.GetComponentsInChildren(UnityTypes.Text.UnityType, true); <>7__wrap2 = 0; goto IL_010d; } goto IL_0124; IL_01a1: if (!Settings.EnableNGUI || UnityTypes.UILabel == null) { break; } <>7__wrap1 = go.GetComponentsInChildren(UnityTypes.UILabel.UnityType, true); <>7__wrap2 = 0; goto IL_0209; } return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__43 d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__43(0); } d__.go = <>3__go; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly Color Transparent; private static readonly string SetAllDirtyMethodName; private static readonly string TexturePropertyName; private static readonly string MainTexturePropertyName; private static readonly string CapitalMainTexturePropertyName; private static readonly string MarkAsChangedMethodName; private static readonly string SupportRichTextPropertyName; private static readonly string RichTextPropertyName; private static GameObject[] _objects; private static readonly string XuaIgnore; private static readonly string XuaIgnoreTree; private static List TexturePropertyMovers; private static readonly Dictionary Manipulators; private static bool _guiContentCheckFailed; static ComponentExtensions() { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) Transparent = new Color(0f, 0f, 0f, 0f); SetAllDirtyMethodName = "SetAllDirty"; TexturePropertyName = "texture"; MainTexturePropertyName = "mainTexture"; CapitalMainTexturePropertyName = "MainTexture"; MarkAsChangedMethodName = "MarkAsChanged"; SupportRichTextPropertyName = "supportRichText"; RichTextPropertyName = "richText"; _objects = (GameObject[])(object)new GameObject[128]; XuaIgnore = "XUAIGNORE"; XuaIgnoreTree = "XUAIGNORETREE"; Manipulators = new Dictionary(); TexturePropertyMovers = new List(); LoadProperty("name"); LoadProperty("anisoLevel"); LoadProperty("filterMode"); LoadProperty("mipMapBias"); LoadProperty("wrapMode"); } private static void LoadProperty(string propertyName) { PropertyInfo property = typeof(TObject).GetProperty(propertyName); if ((object)property != null && property.CanWrite && property.CanRead) { TexturePropertyMovers.Add(new PropertyMover(property)); } } public static ITextComponentManipulator GetTextManipulator(this object ui) { if (ui == null) { return null; } Type unityType = ObjectExtensions.GetUnityType(ui); if (!Manipulators.TryGetValue(unityType, out var value)) { value = ((UnityTypes.TextField != null && UnityTypes.TextField.IsAssignableFrom(unityType)) ? new FairyGUITextComponentManipulator() : ((UnityTypes.TextArea2D != null && UnityTypes.TextArea2D.IsAssignableFrom(unityType)) ? new TextArea2DComponentManipulator() : ((UnityTypes.UguiNovelText == null || !UnityTypes.UguiNovelText.IsAssignableFrom(unityType)) ? ((ITextComponentManipulator)new DefaultTextComponentManipulator(ui.GetType())) : ((ITextComponentManipulator)new UguiNovelTextComponentManipulator(ui.GetType()))))); Manipulators[unityType] = value; } return value; } public static bool ShouldIgnoreTextComponent(this object ui) { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Expected O, but got Unknown //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Expected O, but got Unknown Component val = (Component)((ui is Component) ? ui : null); if (val != null && Object.op_Implicit((Object)(object)val)) { Transform val2 = val.transform; if (((Object)val2).name.Contains(XuaIgnore)) { return true; } while (Object.op_Implicit((Object)(object)val2.parent)) { val2 = val2.parent; if (((Object)val2).name.Contains(XuaIgnoreTree)) { return true; } } Component val3 = null; if (UnityTypes.InputField != null) { GameObject gameObject = val.gameObject; TypeContainer inputField = UnityTypes.InputField; val3 = gameObject.GetFirstComponentInSelfOrAncestor((inputField != null) ? inputField.UnityType : null); if ((Object)(object)val3 != (Object)null && InputField_Properties.Placeholder != null) { Component val4 = (Component)InputField_Properties.Placeholder.Get((object)val3); return !UnityObjectReferenceComparer.Default.Equals((object)val4, (object)val); } } if (UnityTypes.TMP_InputField != null) { GameObject gameObject2 = val.gameObject; TypeContainer tMP_InputField = UnityTypes.TMP_InputField; val3 = gameObject2.GetFirstComponentInSelfOrAncestor((tMP_InputField != null) ? tMP_InputField.UnityType : null); if ((Object)(object)val3 != (Object)null && TMP_InputField_Properties.Placeholder != null) { Component val5 = (Component)TMP_InputField_Properties.Placeholder.Get((object)val3); return !UnityObjectReferenceComparer.Default.Equals((object)val5, (object)val); } } GameObject gameObject3 = val.gameObject; TypeContainer uIInput = UnityTypes.UIInput; val3 = gameObject3.GetFirstComponentInSelfOrAncestor((uIInput != null) ? uIInput.UnityType : null); return (Object)(object)val3 != (Object)null; } return false; } public static bool IsComponentActive(this object ui) { Component val = (Component)((ui is Component) ? ui : null); if (val != null && Object.op_Implicit((Object)(object)val)) { GameObject gameObject = val.gameObject; if (Object.op_Implicit((Object)(object)gameObject)) { Behaviour val2 = (Behaviour)(object)((val is Behaviour) ? val : null); if (val2 != null) { if (gameObject.activeInHierarchy) { return val2.enabled; } return false; } return gameObject.activeInHierarchy; } } return true; } public static bool IsKnownTextType(this object ui) { if (ui == null) { return false; } Type unityType = ObjectExtensions.GetUnityType(ui); if ((!Settings.EnableIMGUI || _guiContentCheckFailed || !IsGUIContentSafe(ui)) && (!Settings.EnableUIElements || UnityTypes.TextElement == null || !UnityTypes.TextElement.IsAssignableFrom(unityType)) && (!Settings.EnableUGUI || UnityTypes.Text == null || !UnityTypes.Text.IsAssignableFrom(unityType)) && (!Settings.EnableNGUI || UnityTypes.UILabel == null || !UnityTypes.UILabel.IsAssignableFrom(unityType)) && (!Settings.EnableTextMesh || UnityTypes.TextMesh == null || !UnityTypes.TextMesh.IsAssignableFrom(unityType)) && (!Settings.EnableFairyGUI || UnityTypes.TextField == null || !UnityTypes.TextField.IsAssignableFrom(unityType))) { if (Settings.EnableTextMeshPro) { return IsKnownTextMeshProType(unityType); } return false; } return true; } public static bool IsKnownTextMeshProType(Type type) { if (UnityTypes.TMP_Text != null) { return UnityTypes.TMP_Text.IsAssignableFrom(type); } TypeContainer textMeshProUGUI = UnityTypes.TextMeshProUGUI; if (textMeshProUGUI == null || !textMeshProUGUI.IsAssignableFrom(type)) { TypeContainer textMeshPro = UnityTypes.TextMeshPro; if (textMeshPro == null) { return false; } return textMeshPro.IsAssignableFrom(type); } return true; } public static bool SupportsRichText(this object ui) { if (ui == null) { return false; } Type type = ui.GetType(); Type unityType = ObjectExtensions.GetUnityType(ui); if (UnityTypes.Text != null && UnityTypes.Text.IsAssignableFrom(unityType)) { CachedProperty obj = ReflectionCache.CachedProperty(type, SupportRichTextPropertyName); if (object.Equals((obj != null) ? obj.Get(ui) : null, true)) { goto IL_00b8; } } if (UnityTypes.TextMesh != null && UnityTypes.TextMesh.IsAssignableFrom(unityType)) { CachedProperty obj2 = ReflectionCache.CachedProperty(type, RichTextPropertyName); if (object.Equals((obj2 != null) ? obj2.Get(ui) : null, true)) { goto IL_00b8; } } if (!DoesTextMeshProSupportRichText(ui, type, unityType) && (UnityTypes.UguiNovelText == null || !UnityTypes.UguiNovelText.IsAssignableFrom(unityType))) { if (UnityTypes.TextField != null) { return UnityTypes.TextField.IsAssignableFrom(unityType); } return false; } goto IL_00b8; IL_00b8: return true; } public static bool DoesTextMeshProSupportRichText(object ui, Type clrType, Type unityType) { if (UnityTypes.TMP_Text != null) { if (UnityTypes.TMP_Text.IsAssignableFrom(unityType)) { CachedProperty obj = ReflectionCache.CachedProperty(clrType, RichTextPropertyName); return object.Equals((obj != null) ? obj.Get(ui) : null, true); } return false; } TypeContainer textMeshPro = UnityTypes.TextMeshPro; if (textMeshPro != null && textMeshPro.IsAssignableFrom(unityType)) { CachedProperty obj2 = ReflectionCache.CachedProperty(clrType, RichTextPropertyName); if (object.Equals((obj2 != null) ? obj2.Get(ui) : null, true)) { return true; } } TypeContainer textMeshProUGUI = UnityTypes.TextMeshProUGUI; if (textMeshProUGUI != null && textMeshProUGUI.IsAssignableFrom(unityType)) { CachedProperty obj3 = ReflectionCache.CachedProperty(clrType, RichTextPropertyName); return object.Equals((obj3 != null) ? obj3.Get(ui) : null, true); } return false; } public static bool SupportsStabilization(this object ui) { if (ui == null) { return false; } if (!_guiContentCheckFailed) { return !IsGUIContentSafe(ui); } return true; } public static bool IsSpammingComponent(this object ui) { if (ui != null) { if (!_guiContentCheckFailed) { return IsGUIContentSafe(ui); } return false; } return true; } private static bool IsGUIContentSafe(object ui) { try { return IsGUIContentUnsafe(ui); } catch { _guiContentCheckFailed = true; } return false; } private static bool IsGUIContentUnsafe(object ui) { return ui is GUIContent; } private static bool SetTextOnGUIContentSafe(object ui, string text) { try { return SetTextOnGUIContentUnsafe(ui, text); } catch { _guiContentCheckFailed = true; } return false; } private static bool SetTextOnGUIContentUnsafe(object ui, string text) { GUIContent val = (GUIContent)((ui is GUIContent) ? ui : null); if (val != null) { val.text = text; return true; } return false; } private static bool TryGetTextFromGUIContentSafe(object ui, out string text) { try { return TryGetTextFromGUIContentUnsafe(ui, out text); } catch { _guiContentCheckFailed = false; } text = null; return false; } private static bool TryGetTextFromGUIContentUnsafe(object ui, out string text) { GUIContent val = (GUIContent)((ui is GUIContent) ? ui : null); if (val != null) { text = val.text; return true; } text = null; return false; } public static bool SupportsLineParser(this object ui) { if (Settings.GameLogTextPaths.Count > 0) { Component val = (Component)((ui is Component) ? ui : null); if (val != null) { return Settings.GameLogTextPaths.Contains(val.gameObject.GetPath()); } } return false; } public static string GetText(this object ui, TextTranslationInfo info) { if (ui == null) { return null; } TextGetterCompatModeHelper.IsGettingText = true; try { string text = null; if ((_guiContentCheckFailed || !TryGetTextFromGUIContentSafe(ui, out text)) && info != null) { return info.TextManipulator.GetText(ui); } return text; } finally { TextGetterCompatModeHelper.IsGettingText = false; } } public static void SetText(this object ui, string text, TextTranslationInfo info) { if (ui != null && (_guiContentCheckFailed || !SetTextOnGUIContentSafe(ui, text))) { info?.TextManipulator.SetText(ui, text); } } public static TextTranslationInfo GetOrCreateTextTranslationInfo(this object ui) { if (!ui.IsSpammingComponent()) { TextTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData(ui); orCreateExtensionData.Initialize(ui); return orCreateExtensionData; } return null; } public static TextTranslationInfo GetTextTranslationInfo(this object ui) { if (!ui.IsSpammingComponent()) { return ExtensionDataHelper.GetExtensionData(ui); } return null; } public static ImageTranslationInfo GetOrCreateImageTranslationInfo(this object obj, Texture2D originalTexture) { if (obj == null) { return null; } ImageTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData(obj); if (orCreateExtensionData.Original == null) { orCreateExtensionData.Initialize(originalTexture); } return orCreateExtensionData; } public static TextureTranslationInfo GetOrCreateTextureTranslationInfo(this Texture2D texture) { TextureTranslationInfo orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData((object)texture); orCreateExtensionData.Initialize(texture); return orCreateExtensionData; } public static object CreateDerivedProxyIfRequiredAndPossible(this Component ui) { if (ui.IsKnownTextType()) { return ui; } return null; } public static Component GetOrCreateNGUIDerivedProxy(this Component ui) { Type unityType = ObjectExtensions.GetUnityType((object)ui); if (UnityTypes.UILabel != null && UnityTypes.UILabel.IsAssignableFrom(unityType)) { return ui; } return null; } public static Component GetFirstComponentInSelfOrAncestor(this GameObject go, Type type) { if ((object)type == null) { return null; } GameObject val = go; while ((Object)(object)val != (Object)null) { Component component = val.GetComponent(type); if ((Object)(object)component != (Object)null) { return component; } Transform transform = val.transform; object obj; if (transform == null) { obj = null; } else { Transform parent = transform.parent; obj = ((parent != null) ? ((Component)parent).gameObject : null); } val = (GameObject)obj; } return null; } public static IEnumerable GetAllTextComponentsInChildren(this GameObject go) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__43(-2) { <>3__go = go }; } private static GameObject GetAssociatedGameObject(object obj) { GameObject val = (GameObject)((obj is GameObject) ? obj : null); if (val == null) { Component val2 = (Component)((obj is Component) ? obj : null); if (val2 == null) { throw new ArgumentException("Expected object to be a GameObject or component.", "obj"); } val = val2.gameObject; } return val; } public static string[] GetPathSegments(this object obj) { GameObject val = GetAssociatedGameObject(obj); int num = 0; int num2 = 0; _objects[num++] = val; while ((Object)(object)val.transform.parent != (Object)null) { val = ((Component)val.transform.parent).gameObject; _objects[num++] = val; } string[] array = new string[num]; while (--num >= 0) { array[num2++] = ((Object)_objects[num]).name; _objects[num] = null; } return array; } public static string GetPath(this object obj) { StringBuilder stringBuilder = new StringBuilder(); string[] pathSegments = obj.GetPathSegments(); for (int i = 0; i < pathSegments.Length; i++) { stringBuilder.Append("/").Append(pathSegments[i]); } return stringBuilder.ToString(); } public static Texture2D GetTexture(this object ui) { if (ui == null) { return null; } SpriteRenderer val = default(SpriteRenderer); if (ObjectExtensions.TryCastTo(ui, ref val)) { Sprite sprite = val.sprite; if (sprite == null) { return null; } return sprite.texture; } Type type = ui.GetType(); CachedProperty obj = ReflectionCache.CachedProperty(type, MainTexturePropertyName); object obj2 = ((obj != null) ? obj.Get(ui) : null); if (obj2 == null) { CachedProperty obj3 = ReflectionCache.CachedProperty(type, TexturePropertyName); obj2 = ((obj3 != null) ? obj3.Get(ui) : null); if (obj2 == null) { CachedProperty obj4 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName); obj2 = ((obj4 != null) ? obj4.Get(ui) : null); } } return (Texture2D)((obj2 is Texture2D) ? obj2 : null); } public static Sprite SetTexture(this object ui, Texture2D texture, Sprite sprite, bool isPrefixHooked) { //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Invalid comparison between Unknown and O if (ui == null) { return null; } Texture2D texture2 = ui.GetTexture(); if (!UnityObjectReferenceComparer.Default.Equals((object)texture2, (object)texture)) { SpriteRenderer sr = default(SpriteRenderer); if (Settings.EnableSpriteRendererHooking && ObjectExtensions.TryCastTo(ui, ref sr)) { if (isPrefixHooked) { return SafeCreateSprite(sr, sprite, texture); } return SafeSetSprite(sr, sprite, texture); } Type type = ui.GetType(); CachedProperty obj = ReflectionCache.CachedProperty(type, MainTexturePropertyName); if (obj != null) { obj.Set(ui, (object)texture); } CachedProperty obj2 = ReflectionCache.CachedProperty(type, TexturePropertyName); if (obj2 != null) { obj2.Set(ui, (object)texture); } CachedProperty obj3 = ReflectionCache.CachedProperty(type, CapitalMainTexturePropertyName); if (obj3 != null) { obj3.Set(ui, (object)texture); } CachedProperty obj4 = ReflectionCache.CachedProperty(type, "material"); object obj5 = ((obj4 != null) ? obj4.Get(ui) : null); if (obj5 != null) { CachedProperty val = ReflectionCache.CachedProperty(obj5.GetType(), MainTexturePropertyName); if ((object)(Texture2D)((val != null) ? val.Get(obj5) : null) == texture2 && val != null) { val.Set(obj5, (object)texture); } } } return null; } private static Sprite SafeSetSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return sr.sprite = Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero); } private static Sprite SafeCreateSprite(SpriteRenderer sr, Sprite sprite, Texture2D texture) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) return Sprite.Create(texture, ((Object)(object)sprite != (Object)null) ? sprite.rect : sr.sprite.rect, Vector2.zero); } public static void SetAllDirtyEx(this object ui) { if (ui != null) { Type unityType = ObjectExtensions.GetUnityType(ui); SpriteRenderer val = default(SpriteRenderer); if (UnityTypes.Graphic != null && UnityTypes.Graphic.IsAssignableFrom(unityType)) { ReflectionCache.CachedMethod(UnityTypes.Graphic.ClrType, SetAllDirtyMethodName).Invoke(ui); } else if (!ObjectExtensions.TryCastTo(ui, ref val)) { AccessToolsShim.Method(ui.GetType(), MarkAsChangedMethodName, new Type[0])?.Invoke(ui, null); } } } public static bool IsKnownImageType(this object ui) { if (ui == null) { return false; } Type unityType = ObjectExtensions.GetUnityType(ui); Material val = default(Material); SpriteRenderer val2 = default(SpriteRenderer); if (!ObjectExtensions.TryCastTo(ui, ref val) && !ObjectExtensions.TryCastTo(ui, ref val2) && (UnityTypes.Image == null || !UnityTypes.Image.IsAssignableFrom(unityType)) && (UnityTypes.RawImage == null || !UnityTypes.RawImage.IsAssignableFrom(unityType)) && (UnityTypes.CubismRenderer == null || !UnityTypes.CubismRenderer.IsAssignableFrom(unityType))) { if (UnityTypes.UIWidget != null) { TypeContainer uILabel = UnityTypes.UILabel; if (!object.Equals(unityType, (uILabel != null) ? uILabel.UnityType : null) && UnityTypes.UIWidget.IsAssignableFrom(unityType)) { goto IL_00cf; } } if ((UnityTypes.UIAtlas == null || !UnityTypes.UIAtlas.IsAssignableFrom(unityType)) && (UnityTypes.UITexture == null || !UnityTypes.UITexture.IsAssignableFrom(unityType))) { if (UnityTypes.UIPanel != null) { return UnityTypes.UIPanel.IsAssignableFrom(unityType); } return false; } } goto IL_00cf; IL_00cf: return true; } public static string GetTextureName(this object texture, string fallbackName) { Texture2D val = default(Texture2D); if (ObjectExtensions.TryCastTo(texture, ref val)) { string name = ((Object)val).name; if (!string.IsNullOrEmpty(name)) { return name; } } return fallbackName; } public static void LoadImageEx(this Texture2D texture, byte[] data, ImageFormat dataType, Texture2D originalTexture) { TextureLoader.Load(texture, data, dataType); if (!((Object)(object)originalTexture != (Object)null)) { return; } foreach (IPropertyMover texturePropertyMover in TexturePropertyMovers) { texturePropertyMover.MoveProperty(originalTexture, texture); } } private static byte[] EncodeToPNGEx(Texture2D texture) { if (ImageConversion_Methods.EncodeToPNG != null) { return ImageConversion_Methods.EncodeToPNG(texture); } if (Texture2D_Methods.EncodeToPNG != null) { return Texture2D_Methods.EncodeToPNG(texture); } throw new NotSupportedException("No way to encode the texture to PNG."); } public static TextureDataResult GetTextureData(this Texture2D texture) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Expected O, but got Unknown //IL_0084: Expected O, but got Unknown float realtimeSinceStartup = Time.realtimeSinceStartup; int width = ((Texture)texture).width; int height = ((Texture)texture).height; byte[] array = null; if (array == null) { RenderTexture temporary = RenderTexture.GetTemporary(width, height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)0); GL.Clear(false, true, Transparent); Graphics.Blit((Texture)(object)texture, temporary); RenderTexture active = RenderTexture.active; RenderTexture.active = temporary; Texture2D val = new Texture2D(width, height); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0); array = EncodeToPNGEx(val); Object.DestroyImmediate((Object)val); RenderTexture.active = (((Object)(object)active == (Object)(object)temporary) ? null : active); RenderTexture.ReleaseTemporary(temporary); } float realtimeSinceStartup2 = Time.realtimeSinceStartup; return new TextureDataResult(array, nonReadable: false, realtimeSinceStartup2 - realtimeSinceStartup); } public static bool IsCompatible(this object texture, ImageFormat dataType) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Invalid comparison between Unknown and I4 //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Invalid comparison between Unknown and I4 //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 TextureFormat format = ((Texture2D)texture).format; switch (dataType) { case ImageFormat.TGA: if ((int)format != 5 && (int)format != 4) { return (int)format == 3; } return true; default: return false; case ImageFormat.PNG: return true; } } } internal static class EnumerableExtensions { public static HashSet ToHashSet(this IEnumerable ts) { HashSet hashSet = new HashSet(); foreach (T t in ts) { hashSet.Add(t); } return hashSet; } public static HashSet ToHashSet(this IEnumerable ts, IEqualityComparer equalityComparer) { HashSet hashSet = new HashSet(equalityComparer); foreach (T t in ts) { hashSet.Add(t); } return hashSet; } public static void AddRange(this ICollection collection, IEnumerable values) { foreach (T value in values) { collection.Add(value); } } } internal static class IniFileExtensions { public static void Set(this IniFile that, string section, string key, T value) { Type type = typeof(T).UnwrapNullable(); IniKey val = that[section][key]; if (value == null) { val.Value = string.Empty; } else if (type.IsEnum) { val.Value = EnumHelper.GetNames(type, value); } else { val.Value = Convert.ToString(value, CultureInfo.InvariantCulture); } } public static T GetOrDefault(this IniFile that, string section, string key, T defaultValue) { Type type = typeof(T).UnwrapNullable(); IniKey val = that[section][key]; try { string value = val.Value; if (value == null) { if (defaultValue != null) { if (type.IsEnum) { val.Value = EnumHelper.GetNames(type, defaultValue); } else { val.Value = Convert.ToString(defaultValue, CultureInfo.InvariantCulture); } } else { val.Value = string.Empty; } return defaultValue; } if (!string.IsNullOrEmpty(value)) { if (type.IsEnum) { return (T)EnumHelper.GetValues(type, val.Value); } return (T)Convert.ChangeType(val.Value, type, CultureInfo.InvariantCulture); } return default(T); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, $"Error occurred while reading config '{key}' in section '{section}'. Updating the config to its default value '{defaultValue}'."); if (defaultValue != null) { if (type.IsEnum) { val.Value = EnumHelper.GetNames(type, defaultValue); } else { val.Value = Convert.ToString(defaultValue, CultureInfo.InvariantCulture); } } else { val.Value = string.Empty; } return defaultValue; } } } public static class StringBuilderExtensions { public static bool EndsWithWhitespaceOrNewline(this StringBuilder builder) { if (builder.Length == 0) { return true; } char c = builder[builder.Length - 1]; if (!char.IsWhiteSpace(c)) { return c == '\n'; } return true; } internal static StringBuilder Reverse(this StringBuilder text) { if (text.Length > 1) { int num = text.Length / 2; for (int i = 0; i < num; i++) { int index = text.Length - (i + 1); char value = text[i]; char value2 = text[index]; text[i] = value2; text[index] = value; } } return text; } } internal static class TypeExtensions { private static Assembly _assemblyCsharp; public static Type UnwrapNullable(this Type type) { return Nullable.GetUnderlyingType(type) ?? type; } public static bool IsAssemblyCsharp(this Assembly assembly) { if ((object)assembly == null) { throw new ArgumentNullException("assembly"); } if ((object)_assemblyCsharp != null) { return _assemblyCsharp.Equals(assembly); } bool num = assembly.GetName().Name.Equals("Assembly-CSharp"); if (num) { _assemblyCsharp = assembly; } return num; } public static bool IsAssemblyCsharpFirstpass(this Assembly assembly) { if ((object)assembly == null) { throw new ArgumentNullException("assembly"); } return assembly.GetName().Name.Equals("Assembly-CSharp-firstpass"); } } internal static class ZipFileExtensions { public static List GetEntries(this ZipFile zf) { List list = new List(); foreach (ZipEntry item in zf) { list.Add(item); } return list; } } } namespace XUnity.AutoTranslator.Plugin.Core.Endpoints { internal static class AssemblyLoader { internal static List GetAllTypesOf(string directory) { Directory.CreateDirectory(directory); string[] files = Directory.GetFiles(directory, "*.dll"); HashSet hashSet = new HashSet(); string[] array = files; for (int i = 0; i < array.Length; i++) { LoadAssembliesInFile(array[i], hashSet); } return hashSet.ToList(); } private static bool LoadAssembliesInFile(string file, HashSet allTypes) { try { Assembly assembly = LoadAssembly(file); if ((object)assembly != null) { foreach (Type item in GetAllTypesOf(assembly)) { allTypes.Add(item); } return true; } } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while loading types in assembly: " + file); } return false; } private static Assembly LoadAssembly(string file) { try { return Assembly.Load(AssemblyName.GetAssemblyName(file)); } catch (BadImageFormatException) { } catch { try { return Assembly.LoadFrom(file); } catch (BadImageFormatException) { } } return null; } internal static List GetAllTypesOf(Assembly assembly) { try { return (from x in assembly.GetTypes() where typeof(TService).IsAssignableFrom(x) && !x.IsAbstract && !x.IsInterface select x).ToList(); } catch (ReflectionTypeLoadException) { return new List(); } } } public class EndpointInitializationException : Exception { public EndpointInitializationException() { } public EndpointInitializationException(string message) : base(message) { } public EndpointInitializationException(string message, Exception inner) : base(message, inner) { } } public interface IInitializationContext { string TranslatorDirectory { get; } string SourceLanguage { get; } string DestinationLanguage { get; } T GetOrCreateSetting(string section, string key, T defaultValue); T GetOrCreateSetting(string section, string key); void SetSetting(string section, string key, T value); void DisableCertificateChecksFor(params string[] hosts); void DisableSpamChecks(); void SetTranslationDelay(float delayInSeconds); } internal class InitializationContext : IInitializationContext { private HttpSecurity _security; public string SourceLanguage { get; } public string DestinationLanguage { get; } public string TranslatorDirectory => Settings.TranslatorsPath; public bool SpamChecksEnabled { get; private set; } public float TranslationDelay { get; private set; } internal InitializationContext(HttpSecurity httpSecurity, string sourceLanguage, string destinationLanguage) { _security = httpSecurity; SourceLanguage = sourceLanguage; DestinationLanguage = destinationLanguage; SpamChecksEnabled = true; TranslationDelay = Settings.DefaultTranslationDelay; } public void DisableCertificateChecksFor(params string[] hosts) { _security.EnableSslFor(hosts); } public void DisableSpamChecks() { SpamChecksEnabled = false; } public T GetOrCreateSetting(string section, string key, T defaultValue) { return PluginEnvironment.Current.Preferences.GetOrDefault(section, key, defaultValue); } public T GetOrCreateSetting(string section, string key) { return PluginEnvironment.Current.Preferences.GetOrDefault(section, key, default(T)); } public void SetSetting(string section, string key, T value) { PluginEnvironment.Current.Preferences.Set(section, key, value); } public void SetTranslationDelay(float delayInSeconds) { if (delayInSeconds < 0.1f) { throw new ArgumentException("delayInSecond must not be lower than 0.1 seconds.", "delayInSeconds"); } TranslationDelay = delayInSeconds; } } public interface ITranslateEndpoint { string Id { get; } string FriendlyName { get; } int MaxConcurrency { get; } int MaxTranslationsPerRequest { get; } void Initialize(IInitializationContext context); IEnumerator Translate(ITranslationContext context); } public interface ITranslationContext : ITranslationContextBase { void Complete(string translatedText); void Complete(string[] translatedTexts); } public interface ITranslationContextBase { string UntranslatedText { get; } string[] UntranslatedTexts { get; } UntranslatedTextInfo UntranslatedTextInfo { get; } UntranslatedTextInfo[] UntranslatedTextInfos { get; } string SourceLanguage { get; } string DestinationLanguage { get; } object UserState { get; set; } void Fail(string reason, Exception exception); void Fail(string reason); } internal sealed class PassthroughTranslateEndpoint : ITranslateEndpoint { public string Id => "Passthrough"; public string FriendlyName => "Passthrough"; public int MaxConcurrency => 50; public int MaxTranslationsPerRequest => 50; public void Initialize(IInitializationContext context) { } public IEnumerator Translate(ITranslationContext context) { context.Complete(context.UntranslatedTexts); return null; } } internal class TranslationContext : ITranslationContext, ITranslationContextBase { private Action _complete; private Action _fail; private string[] _untranslatedTexts; public string UntranslatedText => UntranslatedTexts[0]; public string[] UntranslatedTexts => _untranslatedTexts ?? (_untranslatedTexts = UntranslatedTextInfos.Select((UntranslatedTextInfo x) => x.UntranslatedText).ToArray()); public UntranslatedTextInfo UntranslatedTextInfo => UntranslatedTextInfos[0]; public UntranslatedTextInfo[] UntranslatedTextInfos { get; } public string SourceLanguage { get; } public string DestinationLanguage { get; } internal bool IsDone { get; private set; } public object UserState { get; set; } public TranslationContext(UntranslatedTextInfo[] untranslatedTextInfos, string sourceLanguage, string destinationLanguage, Action complete, Action fail) { UntranslatedTextInfos = untranslatedTextInfos; SourceLanguage = sourceLanguage; DestinationLanguage = destinationLanguage; _complete = complete; _fail = fail; } public void Complete(string translatedText) { Complete(new string[1] { translatedText }); } public void Complete(string[] translatedTexts) { if (IsDone) { return; } try { if (translatedTexts.Length == 0) { _fail("Received empty translation from translator.", null); return; } for (int i = 0; i < translatedTexts.Length; i++) { if (string.IsNullOrEmpty(translatedTexts[0])) { _fail("Received empty translation from translator.", null); return; } } _complete(translatedTexts); } finally { IsDone = true; } } public void Fail(string reason, Exception exception) { if (IsDone) { return; } try { _fail(reason, exception); throw new TranslationContextException(reason, exception); } finally { IsDone = true; } } public void Fail(string reason) { if (IsDone) { return; } try { _fail(reason, null); throw new TranslationContextException(reason); } finally { IsDone = true; } } internal void FailWithoutThrowing(string reason, Exception exception) { if (IsDone) { return; } try { _fail(reason, exception); } finally { IsDone = true; } } internal void FailIfNotCompleted() { if (!IsDone) { FailWithoutThrowing("The translation request was not completed before returning from translator.", null); } } } [Serializable] internal class TranslationContextException : Exception { public TranslationContextException() { } public TranslationContextException(string message) : base(message) { } public TranslationContextException(string message, Exception inner) : base(message, inner) { } protected TranslationContextException(SerializationInfo info, StreamingContext context) : base(info, context) { } } internal class TranslationEndpointManager { private class PriorTranslation { public string UntranslatedText { get; set; } public float Time { get; set; } } [CompilerGenerated] private sealed class d__70 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public TranslationEndpointManager <>4__this; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__70(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { int num = <>1__state; TranslationEndpointManager translationEndpointManager = <>4__this; switch (num) { default: return false; case 0: <>1__state = -1; <>2__current = CoroutineHelper.CreateWaitForSeconds(60f); <>1__state = 1; return true; case 1: <>1__state = -1; translationEndpointManager.HasBatchLogicFailed = false; XuaLogger.AutoTranslator.Info("Re-enabled batching."); return false; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class d__78 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public UntranslatedTextInfo[] untranslatedTextInfos; public string from; public string to; public Action success; public Action failure; public TranslationEndpointManager <>4__this; private float 5__2; private TranslationContext 5__3; private IEnumerator 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__78(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 1) <= 1u) { try { } finally { <>m__Finally1(); } } 5__3 = null; 5__4 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; TranslationEndpointManager translationEndpointManager = <>4__this; bool flag; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = Time.realtimeSinceStartup; 5__3 = new TranslationContext(untranslatedTextInfos, from, to, success, failure); translationEndpointManager._ongoingTranslations++; <>1__state = -3; if (Settings.SimulateDelayedError) { <>2__current = CoroutineHelper.CreateWaitForSeconds(1f); <>1__state = 1; return true; } if (Settings.SimulateError) { 5__3.FailWithoutThrowing("Simulating error. Press CTRL+ALT+NP9 to disable!", null); break; } flag = false; 5__4 = translationEndpointManager.Endpoint.Translate(5__3); if (5__4 != null) { goto IL_00fd; } goto IL_0189; case 1: <>1__state = -3; 5__3.FailWithoutThrowing("Simulating delayed error. Press CTRL+ALT+NP8 to disable!", null); break; case 2: { <>1__state = -3; goto IL_00fd; } IL_00fd: try { flag = 5__4.MoveNext(); if (Time.realtimeSinceStartup - 5__2 > Settings.Timeout) { flag = false; 5__3.FailWithoutThrowing($"Timeout occurred during translation (took more than {Settings.Timeout} seconds)", null); } } catch (TranslationContextException) { flag = false; } catch (Exception exception) { flag = false; 5__3.FailWithoutThrowing("Error occurred during translation.", exception); } if (flag) { <>2__current = 5__4.Current; <>1__state = 2; return true; } goto IL_0189; IL_0189: 5__4 = null; break; } <>m__Finally1(); return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; <>4__this._ongoingTranslations--; 5__3.FailIfNotCompleted(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private List _priorTranslations; private Dictionary _failedTranslations; private Dictionary _unstartedJobs; private Dictionary _ongoingJobs; private int _ongoingTranslations; private Dictionary _translations; private Dictionary _reverseTranslations; public TranslationManager Manager { get; set; } public ITranslateEndpoint Endpoint { get; } public Exception Error { get; } public bool IsBusy => _ongoingTranslations >= Endpoint.MaxConcurrency; public bool HasBatchLogicFailed { get; set; } public int AvailableBatchOperations { get; set; } public int ConsecutiveErrors { get; set; } public bool CanBatch { get { if (Endpoint.MaxTranslationsPerRequest > 1 && _unstartedJobs.Count > 1 && !HasBatchLogicFailed) { return AvailableBatchOperations > 0; } return false; } } public bool HasUnstartedBatch { get { if (_unstartedJobs.Count > 0) { return AvailableBatchOperations > 0; } return false; } } public bool HasUnstartedJob => _unstartedJobs.Count > 0; public bool HasFailedDueToConsecutiveErrors => ConsecutiveErrors >= Settings.MaxErrors; public bool EnableSpamChecks { get; set; } = true; public float TranslationDelay { get; set; } = Settings.DefaultTranslationDelay; public int MaxRetries { get; set; } = Settings.DefaultMaxRetries; public TranslationEndpointManager(ITranslateEndpoint endpoint, Exception error, InitializationContext context) { Endpoint = endpoint; Error = error; _ongoingTranslations = 0; _failedTranslations = new Dictionary(); _unstartedJobs = new Dictionary(); _ongoingJobs = new Dictionary(); _priorTranslations = new List(); _translations = new Dictionary(); _reverseTranslations = new Dictionary(); HasBatchLogicFailed = false; AvailableBatchOperations = Settings.MaxAvailableBatchOperations; EnableSpamChecks = context.SpamChecksEnabled; TranslationDelay = context.TranslationDelay; MaxRetries = (int)(60f / context.TranslationDelay); if (MaxRetries < 3) { MaxRetries = 3; } } public bool TryGetTranslation(UntranslatedText key, out string value) { bool flag; if (key.IsTemplated && !key.IsFromSpammingComponent) { string key2 = key.Untemplate(key.TemplatedOriginal_Text); flag = _translations.TryGetValue(key2, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { key2 = key.Untemplate(key.TemplatedOriginal_Text_ExternallyTrimmed); flag = _translations.TryGetValue(key2, out value); if (flag) { string text = key.LeadingWhitespace + value + key.TrailingWhitespace; string key3 = key.Untemplate(key.TemplatedOriginal_Text); AddTranslationToCache(key3, text); value = text; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { key2 = key.Untemplate(key.TemplatedOriginal_Text_InternallyTrimmed); flag = _translations.TryGetValue(key2, out value); if (flag) { string text = value; string key3 = key.Untemplate(key.TemplatedOriginal_Text); AddTranslationToCache(key3, text); value = text; return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { key2 = key.Untemplate(key.TemplatedOriginal_Text_FullyTrimmed); flag = _translations.TryGetValue(key2, out value); if (flag) { string text = key.LeadingWhitespace + value + key.TrailingWhitespace; string key3 = key.Untemplate(key.TemplatedOriginal_Text); AddTranslationToCache(key3, text); value = text; return flag; } } } flag = _translations.TryGetValue(key.TemplatedOriginal_Text, out value); if (flag) { return flag; } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_ExternallyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_ExternallyTrimmed, out value); if (flag) { string text = key.LeadingWhitespace + value + key.TrailingWhitespace; AddTranslationToCache(key.TemplatedOriginal_Text, text); value = text; return flag; } } if ((object)key.TemplatedOriginal_Text != key.TemplatedOriginal_Text_InternallyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_InternallyTrimmed, out value); if (flag) { AddTranslationToCache(key.TemplatedOriginal_Text, value); return flag; } } if ((object)key.TemplatedOriginal_Text_InternallyTrimmed != key.TemplatedOriginal_Text_FullyTrimmed) { flag = _translations.TryGetValue(key.TemplatedOriginal_Text_FullyTrimmed, out value); if (flag) { string text = key.LeadingWhitespace + value + key.TrailingWhitespace; AddTranslationToCache(key.TemplatedOriginal_Text, text); value = text; return flag; } } return flag; } private void AddTranslation(string key, string value) { if (key != null && value != null) { _translations[key] = value; _reverseTranslations[value] = key; } } private void QueueNewTranslationForDisk(string key, string value) { } public void AddTranslationToCache(string key, string value) { if (!HasTranslated(key)) { AddTranslation(key, value); UntranslatedText untranslatedText = new UntranslatedText(key, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.FromLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); UntranslatedText untranslatedText2 = new UntranslatedText(value, isFromSpammingComponent: false, removeInternalWhitespace: true, Settings.ToLanguageUsesWhitespaceBetweenWords, enableTemplating: true, Settings.TemplateAllNumberAway); if (untranslatedText.Original_Text_ExternallyTrimmed != key && !HasTranslated(untranslatedText.Original_Text_ExternallyTrimmed)) { AddTranslation(untranslatedText.Original_Text_ExternallyTrimmed, untranslatedText2.Original_Text_ExternallyTrimmed); } if (untranslatedText.Original_Text_ExternallyTrimmed != untranslatedText.Original_Text_FullyTrimmed && !HasTranslated(untranslatedText.Original_Text_FullyTrimmed)) { AddTranslation(untranslatedText.Original_Text_FullyTrimmed, untranslatedText2.Original_Text_FullyTrimmed); } QueueNewTranslationForDisk(key, value); } } public bool IsTranslatable(string text) { return !IsTranslation(text); } private bool IsTranslation(string translation) { if (!HasTranslated(translation)) { return _reverseTranslations.ContainsKey(translation); } return false; } private bool HasTranslated(string key) { return _translations.ContainsKey(key); } private string GetTextToTranslate(TranslationJob job) { string text = ((!Settings.IgnoreWhitespaceInDialogue || job.Key.Original_Text.Length <= Settings.MinDialogueChars) ? job.Key.TemplatedOriginal_Text_ExternallyTrimmed : job.Key.TemplatedOriginal_Text_FullyTrimmed); return PreProcessUntranslatedText(text); } public UntranslatedTextInfo PrepareUntranslatedText(string unpreparedUntranslatedText, TranslationJob job) { string untranslatedText = job.Key.PrepareUntranslatedText(unpreparedUntranslatedText); UntranslatedTextInfo untranslatedTextInfo = job.UntranslatedTextInfo; if (untranslatedTextInfo != null) { return new UntranslatedTextInfo(untranslatedText, untranslatedTextInfo.ContextBefore, untranslatedTextInfo.ContextAfter); } return new UntranslatedTextInfo(untranslatedText); } public void HandleNextBatch() { try { List> list = _unstartedJobs.Take(Endpoint.MaxTranslationsPerRequest).ToList(); List list2 = new List(); List list3 = new List(); foreach (KeyValuePair item2 in list) { UntranslatedText key = item2.Key; TranslationJob value = item2.Value; _unstartedJobs.Remove(key); Manager.UnstartedTranslations--; if (value.IsTranslatable) { string textToTranslate = GetTextToTranslate(value); UntranslatedTextInfo item = PrepareUntranslatedText(textToTranslate, value); if (CanTranslate(textToTranslate)) { list3.Add(value); list2.Add(item); _ongoingJobs[key] = value; Manager.OngoingTranslations++; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Started: '" + textToTranslate + "'"); } } else { XuaLogger.AutoTranslator.Warn("Dequeued: '" + textToTranslate + "' because the current endpoint has already failed this translation 3 times."); value.State = TranslationJobState.Failed; value.ErrorMessage = "The endpoint failed to perform this translation 3 or more times."; InvokeJobFailedWithFallbaack(value); } } else { _ongoingJobs[key] = value; Manager.OngoingTranslations++; OnSingleTranslationCompleted(value, new string[1] { key.TemplatedOriginal_Text_ExternallyTrimmed }, useTranslatorFriendlyArgs: false); } } if (list3.Count > 0) { AvailableBatchOperations--; TranslationJob[] jobsArray = list3.ToArray(); CoroutineHelper.Start(Translate(list2.ToArray(), Settings.FromLanguage, Settings.Language, delegate(string[] translatedText) { OnBatchTranslationCompleted(jobsArray, translatedText); }, delegate(string msg, Exception e) { OnTranslationFailed(jobsArray, msg, e); })); } } finally { if (_unstartedJobs.Count == 0) { Manager.UnscheduleUnstartedJobs(this); } } } public void HandleNextJob() { try { KeyValuePair keyValuePair = _unstartedJobs.FirstOrDefault(); UntranslatedText key = keyValuePair.Key; TranslationJob job = keyValuePair.Value; _unstartedJobs.Remove(key); Manager.UnstartedTranslations--; if (job.IsTranslatable) { string textToTranslate = GetTextToTranslate(job); UntranslatedTextInfo untranslatedTextInfo = PrepareUntranslatedText(textToTranslate, job); if (CanTranslate(textToTranslate)) { _ongoingJobs[key] = job; Manager.OngoingTranslations++; if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Started: '" + textToTranslate + "'"); } CoroutineHelper.Start(Translate(new UntranslatedTextInfo[1] { untranslatedTextInfo }, Settings.FromLanguage, Settings.Language, delegate(string[] translatedText) { OnSingleTranslationCompleted(job, translatedText, useTranslatorFriendlyArgs: true); }, delegate(string msg, Exception e) { OnTranslationFailed(new TranslationJob[1] { job }, msg, e); })); } else { XuaLogger.AutoTranslator.Warn("Dequeued: '" + textToTranslate + "' because the current endpoint has already failed this translation 3 times."); job.State = TranslationJobState.Failed; job.ErrorMessage = "The endpoint failed to perform this translation 3 or more times."; InvokeJobFailedWithFallbaack(job); } } else { _ongoingJobs[key] = job; Manager.OngoingTranslations++; OnSingleTranslationCompleted(job, new string[1] { key.TemplatedOriginal_Text_ExternallyTrimmed }, useTranslatorFriendlyArgs: false); } } finally { if (_unstartedJobs.Count == 0) { Manager.UnscheduleUnstartedJobs(this); } } } private void OnBatchTranslationCompleted(TranslationJob[] jobs, string[] translatedTexts) { ConsecutiveErrors = 0; if (jobs.Length == translatedTexts.Length) { for (int i = 0; i < jobs.Length; i++) { TranslationJob translationJob = jobs[i]; string translatedText = translatedTexts[i]; translationJob.TranslatedText = PostProcessTranslation(translationJob.Key, translatedText, useTranslatorFriendlyArgs: true); translationJob.State = TranslationJobState.Succeeded; RemoveOngoingTranslation(translationJob.Key); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Completed: '" + translationJob.Key.TemplatedOriginal_Text + "' => '" + translationJob.TranslatedText + "'"); } Manager.InvokeJobCompleted(translationJob); } } else { if (!HasBatchLogicFailed) { CoroutineHelper.Start(EnableBatchingAfterDelay()); } HasBatchLogicFailed = true; foreach (TranslationJob translationJob2 in jobs) { UntranslatedText key = translationJob2.Key; AddUnstartedJob(key, translationJob2); RemoveOngoingTranslation(key); } XuaLogger.AutoTranslator.Error("A batch operation failed. Disabling batching and restarting failed jobs."); } } private void OnSingleTranslationCompleted(TranslationJob job, string[] translatedTexts, bool useTranslatorFriendlyArgs) { string translatedText = translatedTexts[0]; ConsecutiveErrors = 0; job.TranslatedText = PostProcessTranslation(job.Key, translatedText, useTranslatorFriendlyArgs); job.State = TranslationJobState.Succeeded; RemoveOngoingTranslation(job.Key); if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Info("Completed: '" + job.Key.TemplatedOriginal_Text + "' => '" + job.TranslatedText + "'"); } Manager.InvokeJobCompleted(job); } private string PostProcessTranslation(UntranslatedText key, string translatedText, bool useTranslatorFriendlyArgs) { if (!string.IsNullOrEmpty(translatedText)) { translatedText = key.FixTranslatedText(translatedText, useTranslatorFriendlyArgs); translatedText = key.LeadingWhitespace + translatedText + key.TrailingWhitespace; if (Settings.Language == Settings.Romaji && Settings.RomajiPostProcessing != 0) { translatedText = RomanizationHelper.PostProcess(translatedText, Settings.RomajiPostProcessing); } else if (Settings.TranslationPostProcessing != 0) { translatedText = RomanizationHelper.PostProcess(translatedText, Settings.TranslationPostProcessing); } foreach (KeyValuePair postprocessor in Settings.Postprocessors) { translatedText = translatedText.Replace(postprocessor.Key, postprocessor.Value); } if (Settings.ForceSplitTextAfterCharacters > 0) { translatedText = StringExtensions.SplitToLines(translatedText, Settings.ForceSplitTextAfterCharacters, new char[3] { '\n', ' ', '\u3000' }); } } return translatedText; } private string PreProcessUntranslatedText(string text) { if (Settings.HtmlEntityPreprocessing) { text = XUnity.AutoTranslator.Plugin.Core.Shims.WebUtility.HtmlDecode(text); } if (Settings.Preprocessors.Count == 0) { return text; } foreach (KeyValuePair preprocessor in Settings.Preprocessors) { text = text.Replace(preprocessor.Key, preprocessor.Value); } return text; } private void OnTranslationFailed(TranslationJob[] jobs, string error, Exception e) { if (e == null) { XuaLogger.AutoTranslator.Error(error); } else { XuaLogger.AutoTranslator.Error(e, error); } if (jobs.Length == 1) { foreach (TranslationJob translationJob in jobs) { UntranslatedText key = translationJob.Key; translationJob.State = TranslationJobState.Failed; translationJob.ErrorMessage = error; RemoveOngoingTranslation(key); RegisterTranslationFailureFor(key.TemplatedOriginal_Text); XuaLogger.AutoTranslator.Error("Failed: '" + translationJob.Key.TemplatedOriginal_Text + "'"); InvokeJobFailedWithFallbaack(translationJob); } } else { if (!HasBatchLogicFailed) { CoroutineHelper.Start(EnableBatchingAfterDelay()); } HasBatchLogicFailed = true; foreach (TranslationJob translationJob2 in jobs) { UntranslatedText key2 = translationJob2.Key; AddUnstartedJob(key2, translationJob2); RemoveOngoingTranslation(key2); XuaLogger.AutoTranslator.Error("Failed: '" + translationJob2.Key.TemplatedOriginal_Text + "'"); } XuaLogger.AutoTranslator.Error("A batch operation failed. Disabling batching and restarting failed jobs."); } if (!HasFailedDueToConsecutiveErrors) { ConsecutiveErrors++; if (HasFailedDueToConsecutiveErrors) { XuaLogger.AutoTranslator.Error($"{Settings.MaxErrors} or more consecutive errors occurred. Shutting down translator endpoint."); ClearAllJobs(); } } } private void InvokeJobFailedWithFallbaack(TranslationJob job) { if (job.AllowFallback && Manager.IsFallbackAvailableFor(this) && !Manager.FallbackEndpoint.HasFailedDueToConsecutiveErrors) { XuaLogger.AutoTranslator.Warn("Retrying translation for '" + job.Key.TemplatedOriginal_Text + "' against fallback endpoint instead."); job.Endpoint = Manager.FallbackEndpoint; Manager.FallbackEndpoint.AddUnstartedJob(job.Key, job); } else { Manager.InvokeJobFailed(job); } } private IEnumerator EnableBatchingAfterDelay() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__70(0) { <>4__this = this }; } public TranslationJob EnqueueTranslation(object ui, UntranslatedText key, InternalTranslationResult translationResult, ParserTranslationContext context, UntranslatedTextInfo untranslatedTextContext, bool checkOtherEndpoints, bool saveResultGlobally, bool isTranslatable, bool allowFallback) { if (AssociateWithExistingJobIfPossible(ui, key, translationResult, context, untranslatedTextContext, saveResultGlobally, allowFallback)) { return null; } if (checkOtherEndpoints) { List configuredEndpoints = Manager.ConfiguredEndpoints; int count = configuredEndpoints.Count; for (int i = 0; i < count; i++) { TranslationEndpointManager translationEndpointManager = configuredEndpoints[i]; if (translationEndpointManager != this && translationEndpointManager.AssociateWithExistingJobIfPossible(ui, key, translationResult, context, untranslatedTextContext, saveResultGlobally, allowFallback)) { return null; } } } if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Queued: '" + key.TemplatedOriginal_Text + "'"); } TranslationJob translationJob = new TranslationJob(this, key, saveResultGlobally, isTranslatable); translationJob.Associate(key, ui, translationResult, context, untranslatedTextContext, saveResultGlobally, allowFallback); return AddUnstartedJob(key, translationJob); } private bool AssociateWithExistingJobIfPossible(object ui, UntranslatedText key, InternalTranslationResult translationResult, ParserTranslationContext context, UntranslatedTextInfo untranslatedTextContext, bool saveResultGlobally, bool allowFallback) { if (_unstartedJobs.TryGetValue(key, out var value)) { value.Associate(key, ui, translationResult, context, untranslatedTextContext, saveResultGlobally, allowFallback); return true; } if (_ongoingJobs.TryGetValue(key, out var value2)) { value2.Associate(key, ui, translationResult, context, untranslatedTextContext, saveResultGlobally, allowFallback); return true; } return false; } private TranslationJob AddUnstartedJob(UntranslatedText key, TranslationJob job) { if (!_unstartedJobs.ContainsKey(key)) { int count = _unstartedJobs.Count; _unstartedJobs.Add(key, job); Manager.UnstartedTranslations++; if (count == 0) { Manager.ScheduleUnstartedJobs(this); } return job; } return null; } private void RemoveOngoingTranslation(UntranslatedText key) { if (_ongoingJobs.Remove(key)) { Manager.OngoingTranslations--; } } public void ClearAllJobs() { int count = _ongoingJobs.Count; int count2 = _unstartedJobs.Count; List> list = _unstartedJobs.ToList(); _ongoingJobs.Clear(); _unstartedJobs.Clear(); foreach (KeyValuePair item in list) { XuaLogger.AutoTranslator.Warn("Dequeued: '" + item.Key.TemplatedOriginal_Text + "'"); item.Value.State = TranslationJobState.Failed; item.Value.ErrorMessage = "Translation failed because all jobs on endpoint was cleared."; Manager.InvokeJobFailed(item.Value); } Manager.OngoingTranslations -= count; Manager.UnstartedTranslations -= count2; Manager.UnscheduleUnstartedJobs(this); } private bool CanTranslate(string untranslatedText) { if (_failedTranslations.TryGetValue(untranslatedText, out var value)) { return value < Settings.MaxFailuresForSameTextPerEndpoint; } return true; } private void RegisterTranslationFailureFor(string untranslatedText) { byte value = (byte)((!_failedTranslations.TryGetValue(untranslatedText, out value)) ? 1 : ((byte)(value + 1))); _failedTranslations[untranslatedText] = value; } public IEnumerator Translate(UntranslatedTextInfo[] untranslatedTextInfos, string from, string to, Action success, Action failure) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__78(0) { <>4__this = this, untranslatedTextInfos = untranslatedTextInfos, from = from, to = to, success = success, failure = failure }; } } public class UntranslatedTextInfo { public List ContextBefore { get; } public string UntranslatedText { get; internal set; } public List ContextAfter { get; } internal UntranslatedTextInfo(string untranslatedText) { UntranslatedText = untranslatedText; ContextBefore = new List(); ContextAfter = new List(); } internal UntranslatedTextInfo(string untranslatedText, List contextBefore, List contextAfter) { UntranslatedText = untranslatedText; ContextBefore = contextBefore; ContextAfter = contextAfter; } public TransmittableUntranslatedTextInfo ToTransmittable() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown return new TransmittableUntranslatedTextInfo(ContextBefore.ToArray(), UntranslatedText, ContextAfter.ToArray()); } } } namespace XUnity.AutoTranslator.Plugin.Core.Endpoints.Www { public interface IWwwRequestCreationContext : IWwwTranslationContext, ITranslationContextBase { void Complete(WwwRequestInfo requestInfo); } public interface IWwwTranslationContext : ITranslationContextBase { } public interface IWwwTranslationExtractionContext : IWwwTranslationContext, ITranslationContextBase { string ResponseData { get; } void Complete(string translatedText); void Complete(string[] translatedTexts); } public abstract class WwwEndpoint : ITranslateEndpoint { [CompilerGenerated] private sealed class d__13 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ITranslationContext context; public WwwEndpoint <>4__this; private WwwTranslationContext 5__2; private IEnumerator 5__3; private WWW 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; 5__4 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; WwwEndpoint wwwEndpoint = <>4__this; WwwRequestInfo requestInfo; string data; Dictionary headers; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = new WwwTranslationContext(context); 5__3 = wwwEndpoint.OnBeforeTranslate(5__2); if (5__3 != null) { goto IL_0077; } goto IL_0084; case 1: <>1__state = -1; goto IL_0077; case 2: { <>1__state = -1; string error = 5__4.error; if (error != null) { 5__2.Fail("Error occurred while retrieving translation. " + error); } string text = 5__4.text; if (text == null) { 5__2.Fail("Error occurred while extracting text from response."); } 5__2.ResponseData = text; wwwEndpoint.OnExtractTranslation(5__2); return false; } IL_0077: if (5__3.MoveNext()) { <>2__current = 5__3.Current; <>1__state = 1; return true; } goto IL_0084; IL_0084: wwwEndpoint.OnCreateRequest(5__2); if (5__2.RequestInfo == null) { 5__2.Fail("No request object was provided by the translator."); } requestInfo = 5__2.RequestInfo; _ = requestInfo.Address; data = requestInfo.Data; headers = requestInfo.Headers; 5__4 = wwwEndpoint.CreateWww(requestInfo.Address, (data != null) ? Encoding.UTF8.GetBytes(data) : null, headers); <>2__current = 5__4; <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public abstract string Id { get; } public abstract string FriendlyName { get; } public virtual int MaxConcurrency => 1; public virtual int MaxTranslationsPerRequest => 1; public virtual IEnumerator OnBeforeTranslate(IWwwTranslationContext context) { return null; } public abstract void Initialize(IInitializationContext context); public abstract void OnCreateRequest(IWwwRequestCreationContext context); public abstract void OnExtractTranslation(IWwwTranslationExtractionContext context); protected WWW CreateWww(string address, byte[] data, Dictionary headers) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Expected O, but got Unknown return new WWW(address, data, headers); } public IEnumerator Translate(ITranslationContext context) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__13(0) { <>4__this = this, context = context }; } } public class WwwRequestInfo { private Dictionary _headers; public string Address { get; private set; } public string Data { get; private set; } public Dictionary Headers { get { if (_headers == null) { _headers = new Dictionary(); } return _headers; } set { _headers = value; } } public WwwRequestInfo(string address) { Address = address; } public WwwRequestInfo(string address, string data) { Address = address; Data = data; } } internal class WwwTranslationContext : IWwwTranslationContext, ITranslationContextBase, IWwwRequestCreationContext, IWwwTranslationExtractionContext { private readonly ITranslationContext _context; public string[] UntranslatedTexts => _context.UntranslatedTexts; public string UntranslatedText => _context.UntranslatedText; public UntranslatedTextInfo UntranslatedTextInfo => _context.UntranslatedTextInfo; public UntranslatedTextInfo[] UntranslatedTextInfos => _context.UntranslatedTextInfos; public string SourceLanguage => _context.SourceLanguage; public string DestinationLanguage => _context.DestinationLanguage; public string ResponseData { get; internal set; } internal WwwRequestInfo RequestInfo { get; private set; } public object UserState { get { return _context.UserState; } set { _context.UserState = value; } } internal WwwTranslationContext(ITranslationContext context) { _context = context; } void IWwwRequestCreationContext.Complete(WwwRequestInfo requestInfo) { RequestInfo = requestInfo; } void IWwwTranslationExtractionContext.Complete(string translatedText) { _context.Complete(translatedText); } void IWwwTranslationExtractionContext.Complete(string[] translatedTexts) { _context.Complete(translatedTexts); } public void Fail(string reason, Exception exception) { _context.Fail(reason, exception); } public void Fail(string reason) { _context.Fail(reason); } } } namespace XUnity.AutoTranslator.Plugin.Core.Endpoints.Http { public abstract class HttpEndpoint : ITranslateEndpoint { [CompilerGenerated] private sealed class d__13 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ITranslationContext context; public HttpEndpoint <>4__this; private HttpTranslationContext 5__2; private IEnumerator 5__3; private XUnityWebResponse 5__4; private IEnumerator 5__5; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__13(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; 5__4 = null; 5__5 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; HttpEndpoint httpEndpoint = <>4__this; XUnityWebClient xUnityWebClient; switch (num) { default: return false; case 0: <>1__state = -1; 5__2 = new HttpTranslationContext(context); 5__3 = httpEndpoint.OnBeforeTranslate(5__2); if (5__3 != null) { goto IL_0077; } goto IL_0084; case 1: <>1__state = -1; goto IL_0077; case 2: { <>1__state = -1; break; } IL_0077: if (5__3.MoveNext()) { <>2__current = 5__3.Current; <>1__state = 1; return true; } goto IL_0084; IL_0084: httpEndpoint.OnCreateRequest(5__2); if (5__2.Request == null) { 5__2.Fail("No request object was provided by the translator."); } xUnityWebClient = new XUnityWebClient(); 5__4 = xUnityWebClient.Send(5__2.Request); 5__5 = 5__4.GetSupportedEnumerator(); break; } if (5__5.MoveNext()) { <>2__current = 5__5.Current; <>1__state = 2; return true; } if (5__4.IsTimedOut) { 5__2.Fail("Error occurred while retrieving translation. Timeout."); } 5__2.Response = 5__4; httpEndpoint.OnInspectResponse(5__2); if (5__4.Error != null) { 5__2.Fail("Error occurred while retrieving translation.", 5__4.Error); } if (5__4.Data == null) { 5__2.Fail("Error occurred while retrieving translation. Nothing was returned."); } httpEndpoint.OnExtractTranslation(5__2); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } public abstract string Id { get; } public abstract string FriendlyName { get; } public virtual int MaxConcurrency => 1; public virtual int MaxTranslationsPerRequest => 1; public abstract void Initialize(IInitializationContext context); public virtual IEnumerator OnBeforeTranslate(IHttpTranslationContext context) { return null; } public abstract void OnCreateRequest(IHttpRequestCreationContext context); public virtual void OnInspectResponse(IHttpResponseInspectionContext context) { } public abstract void OnExtractTranslation(IHttpTranslationExtractionContext context); public IEnumerator Translate(ITranslationContext context) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__13(0) { <>4__this = this, context = context }; } } internal class HttpTranslationContext : IHttpTranslationContext, ITranslationContextBase, IHttpRequestCreationContext, IHttpResponseInspectionContext, IHttpTranslationExtractionContext { private readonly ITranslationContext _context; public string UntranslatedText => _context.UntranslatedText; public string[] UntranslatedTexts => _context.UntranslatedTexts; public UntranslatedTextInfo UntranslatedTextInfo => _context.UntranslatedTextInfo; public UntranslatedTextInfo[] UntranslatedTextInfos => _context.UntranslatedTextInfos; public string SourceLanguage => _context.SourceLanguage; public string DestinationLanguage => _context.DestinationLanguage; public XUnityWebResponse Response { get; internal set; } public XUnityWebRequest Request { get; internal set; } public object UserState { get { return _context.UserState; } set { _context.UserState = value; } } internal HttpTranslationContext(ITranslationContext context) { _context = context; } public void Fail(string reason, Exception exception) { _context.Fail(reason, exception); } public void Fail(string reason) { _context.Fail(reason); } void IHttpRequestCreationContext.Complete(XUnityWebRequest request) { Request = request; } void IHttpTranslationExtractionContext.Complete(string translatedText) { _context.Complete(translatedText); } void IHttpTranslationExtractionContext.Complete(string[] translatedTexts) { _context.Complete(translatedTexts); } } public interface IHttpRequestCreationContext : IHttpTranslationContext, ITranslationContextBase { void Complete(XUnityWebRequest request); } public interface IHttpResponseInspectionContext : IHttpTranslationContext, ITranslationContextBase { XUnityWebRequest Request { get; } XUnityWebResponse Response { get; } } public interface IHttpTranslationContext : ITranslationContextBase { } public interface IHttpTranslationExtractionContext : IHttpResponseInspectionContext, IHttpTranslationContext, ITranslationContextBase { void Complete(string translatedText); void Complete(string[] translatedTexts); } } namespace XUnity.AutoTranslator.Plugin.Core.Endpoints.ExtProtocol { public abstract class ExtProtocolEndpoint : IMonoBehaviour_Update, ITranslateEndpoint, IDisposable { [CompilerGenerated] private sealed class d__46 : IEnumerator, IDisposable, IEnumerator { private int <>1__state; private object <>2__current; public ExtProtocolEndpoint <>4__this; public ITranslationContext context; private ProtocolTransactionHandle 5__2; private IEnumerator 5__3; private float 5__4; object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__46(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { 5__2 = null; 5__3 = null; <>1__state = -2; } private bool MoveNext() { //IL_01ad: Unknown result type (might be due to invalid IL or missing references) //IL_01b2: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Expected O, but got Unknown int num = <>1__state; ExtProtocolEndpoint extProtocolEndpoint = <>4__this; float num2; float num3; Guid guid; switch (num) { default: return false; case 0: <>1__state = -1; extProtocolEndpoint.EnsureInitialized(); goto IL_007e; case 1: <>1__state = -1; goto IL_007e; case 2: <>1__state = -1; goto IL_007e; case 3: <>1__state = -1; goto IL_015e; case 4: <>1__state = -1; goto IL_014c; case 5: { <>1__state = -1; break; } IL_007e: if (extProtocolEndpoint._initializing && !extProtocolEndpoint._failed) { object obj = CoroutineHelper.CreateWaitForSecondsRealtime(0.2f); if (obj != null) { <>2__current = obj; <>1__state = 1; return true; } <>2__current = null; <>1__state = 2; return true; } if (extProtocolEndpoint._failed) { context.Fail("External process failed."); } num2 = ((float)Rng.Next((int)((extProtocolEndpoint.MaxDelay - extProtocolEndpoint.MinDelay) * 1000f)) + extProtocolEndpoint.MinDelay * 1000f) / 1000f; num3 = TimeSupport.Time.realtimeSinceStartup - extProtocolEndpoint._lastRequestTimestamp; if (num3 < num2) { float num4 = num2 - num3; object obj2 = CoroutineHelper.CreateWaitForSecondsRealtime(num4); if (obj2 != null) { <>2__current = obj2; <>1__state = 3; return true; } float realtimeSinceStartup = TimeSupport.Time.realtimeSinceStartup; 5__4 = realtimeSinceStartup + num4; goto IL_014c; } goto IL_015e; IL_014c: if (TimeSupport.Time.realtimeSinceStartup < 5__4) { <>2__current = null; <>1__state = 4; return true; } goto IL_015e; IL_015e: extProtocolEndpoint._lastRequestTimestamp = TimeSupport.Time.realtimeSinceStartup; 5__2 = new ProtocolTransactionHandle(); guid = Guid.NewGuid(); lock (extProtocolEndpoint._sync) { extProtocolEndpoint._transactionHandles[guid] = 5__2; } try { string value = ExtProtocolConvert.Encode((ProtocolMessage)new TranslationRequest { Id = guid, SourceLanguage = context.SourceLanguage, DestinationLanguage = context.DestinationLanguage, UntranslatedTextInfos = context.UntranslatedTextInfos.Select((UntranslatedTextInfo x) => x.ToTransmittable()).ToArray() }); extProtocolEndpoint._process.StandardInput.WriteLine(value); } catch (Exception ex) { 5__2.SetCompleted(null, ex.Message, (StatusCode)1000); } 5__3 = 5__2.GetSupportedEnumerator(); break; } if (5__3.MoveNext()) { <>2__current = 5__3.Current; <>1__state = 5; return true; } if (!5__2.Succeeded) { context.Fail("Error occurred while retrieving translation. " + 5__2.Error); } context.Complete(5__2.Results); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static readonly Random Rng = new Random(); private readonly Dictionary _transactionHandles = new Dictionary(); private readonly object _sync = new object(); private bool _disposed; private Process _process; private Thread _thread; private bool _startedThread; private bool _initializing; private bool _failed; private float _lastRequestTimestamp; private string _gameRoot; public abstract string Id { get; } public abstract string FriendlyName { get; } public virtual int MaxConcurrency => 1; public virtual int MaxTranslationsPerRequest => 1; protected string ExecutablePath { get; set; } protected string Arguments { get; set; } protected float MinDelay { get; set; } protected float MaxDelay { get; set; } protected virtual string ConfigurationSectionName => null; protected string ConfigForExternalProcess { get; set; } public virtual void Initialize(IInitializationContext context) { _gameRoot = Paths.GameRoot; string text = null; if (ConfigurationSectionName != null) { text = context.GetOrCreateSetting(ConfigurationSectionName, "ExecutableLocation", null); } if (string.IsNullOrEmpty(text)) { text = Path.Combine(context.TranslatorDirectory, "FullNET\\Common.ExtProtocol.Executor.exe"); } if (!File.Exists(text)) { throw new EndpointInitializationException("Could not find any executable at '" + text + "'"); } ExecutablePath = text; } private void EnsureInitialized() { if (!_startedThread) { _startedThread = true; _initializing = true; _thread = new Thread(ReaderLoop); _thread.IsBackground = true; _thread.Start(); } } private void ReaderLoop(object state) { try { if (_process == null) { string text = ExecutablePath; if (!Path.IsPathRooted(text)) { try { text = Path.Combine(_gameRoot, ExecutablePath); } catch { text = Path.Combine(Environment.CurrentDirectory, ExecutablePath); } } _process = new Process(); _process.StartInfo.FileName = text; _process.StartInfo.Arguments = Arguments; _process.StartInfo.WorkingDirectory = new FileInfo(ExecutablePath).Directory.FullName; _process.EnableRaisingEvents = false; _process.StartInfo.UseShellExecute = false; _process.StartInfo.CreateNoWindow = true; _process.StartInfo.RedirectStandardInput = true; _process.StartInfo.RedirectStandardOutput = true; _process.StartInfo.RedirectStandardError = true; _process.Start(); _process.WaitForExit(2500); } if (!_process.HasExited) { SendConfigurationIfRequired(); _initializing = false; while (!_disposed) { ProtocolMessage message = ExtProtocolConvert.Decode(_process.StandardOutput.ReadLine()); HandleProtocolMessageResponse(message); } } } catch (Exception ex) { _failed = true; _initializing = false; XuaLogger.AutoTranslator.Error(ex, "Error occurred while reading standard output from external process."); } } public virtual void Update() { if (TimeSupport.Time.frameCount % 30 != 0) { return; } lock (_sync) { float realtimeSinceStartup = TimeSupport.Time.realtimeSinceStartup; List list = null; foreach (KeyValuePair transactionHandle in _transactionHandles) { if (realtimeSinceStartup - transactionHandle.Value.StartTime > 60f) { if (list == null) { list = new List(); } list.Add(transactionHandle.Key); transactionHandle.Value.SetCompleted(null, "Request timed out.", (StatusCode)1000); } } if (list == null) { return; } foreach (Guid item in list) { _transactionHandles.Remove(item); } } } private void SendConfigurationIfRequired() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown string configForExternalProcess = ConfigForExternalProcess; if (configForExternalProcess != null) { Guid id = Guid.NewGuid(); try { string value = ExtProtocolConvert.Encode((ProtocolMessage)new ConfigurationMessage { Id = id, Config = configForExternalProcess }); _process.StandardInput.WriteLine(value); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while sending configuration to external process for '" + GetType().Name + "'."); } } } public IEnumerator Translate(ITranslationContext context) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__46(0) { <>4__this = this, context = context }; } private void HandleProtocolMessageResponse(ProtocolMessage message) { TranslationResponse val = (TranslationResponse)(object)((message is TranslationResponse) ? message : null); if (val == null) { TranslationError val2 = (TranslationError)(object)((message is TranslationError) ? message : null); if (val2 != null) { HandleTranslationError(val2); } } else { HandleTranslationResponse(val); } } private void HandleTranslationResponse(TranslationResponse message) { lock (_sync) { if (_transactionHandles.TryGetValue(((ProtocolMessage)message).Id, out var value)) { value.SetCompleted(message.TranslatedTexts, null, (StatusCode)0); _transactionHandles.Remove(((ProtocolMessage)message).Id); } } } private void HandleTranslationError(TranslationError message) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) lock (_sync) { if (_transactionHandles.TryGetValue(((ProtocolMessage)message).Id, out var value)) { value.SetCompleted(null, message.Reason, message.FailureCode); _transactionHandles.Remove(((ProtocolMessage)message).Id); } } } protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing && _process != null) { _process.Dispose(); _thread.Abort(); } _disposed = true; } } public void Dispose() { Dispose(disposing: true); } } internal class ProtocolTransactionHandle : CustomYieldInstructionShim { public override bool keepWaiting => !IsCompleted; public float StartTime { get; set; } public string[] Results { get; set; } public string Error { get; set; } public StatusCode StatusCode { get; set; } public bool IsCompleted { get; private set; } public bool Succeeded => Error == null; public ProtocolTransactionHandle() { StartTime = TimeSupport.Time.realtimeSinceStartup; } public void SetCompleted(string[] translatedTexts, string error, StatusCode statusCode) { IsCompleted = true; Results = translatedTexts; Error = error; } } } namespace XUnity.AutoTranslator.Plugin.Core.Debugging { internal class ConsoleEncoding : Encoding { private byte[] _byteBuffer = new byte[256]; private char[] _charBuffer = new char[256]; private byte[] _zeroByte = new byte[0]; private char[] _zeroChar = new char[0]; private readonly uint _codePage; public override int CodePage => (int)_codePage; private ConsoleEncoding(uint codePage) { _codePage = codePage; } public static ConsoleEncoding GetEncoding(uint codePage) { return new ConsoleEncoding(codePage); } public override int GetByteCount(char[] chars, int index, int count) { WriteCharBuffer(chars, index, count); return Kernel32.WideCharToMultiByte(_codePage, 0u, _charBuffer, count, _zeroByte, 0, IntPtr.Zero, IntPtr.Zero); } public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex) { int maxByteCount = GetMaxByteCount(charCount); WriteCharBuffer(chars, charIndex, charCount); ExpandByteBuffer(maxByteCount); int result = Kernel32.WideCharToMultiByte(_codePage, 0u, chars, charCount, _byteBuffer, maxByteCount, IntPtr.Zero, IntPtr.Zero); ReadByteBuffer(bytes, byteIndex, maxByteCount); return result; } public override int GetCharCount(byte[] bytes, int index, int count) { WriteByteBuffer(bytes, index, count); return Kernel32.MultiByteToWideChar(_codePage, 0u, bytes, count, _zeroChar, 0); } public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex) { int maxCharCount = GetMaxCharCount(byteCount); WriteByteBuffer(bytes, byteIndex, byteCount); ExpandCharBuffer(maxCharCount); int result = Kernel32.MultiByteToWideChar(_codePage, 0u, bytes, byteCount, _charBuffer, maxCharCount); ReadCharBuffer(chars, charIndex, maxCharCount); return result; } public override int GetMaxByteCount(int charCount) { return charCount * 2; } public override int GetMaxCharCount(int byteCount) { return byteCount; } private void ExpandByteBuffer(int count) { if (_byteBuffer.Length < count) { _byteBuffer = new byte[count]; } } private void ExpandCharBuffer(int count) { if (_charBuffer.Length < count) { _charBuffer = new char[count]; } } private void ReadByteBuffer(byte[] bytes, int index, int count) { for (int i = 0; i < count; i++) { bytes[index + i] = _byteBuffer[i]; } } private void ReadCharBuffer(char[] chars, int index, int count) { for (int i = 0; i < count; i++) { chars[index + i] = _charBuffer[i]; } } private void WriteByteBuffer(byte[] bytes, int index, int count) { ExpandByteBuffer(count); for (int i = 0; i < count; i++) { _byteBuffer[i] = bytes[index + i]; } } private void WriteCharBuffer(char[] chars, int index, int count) { ExpandCharBuffer(count); for (int i = 0; i < count; i++) { _charBuffer[i] = chars[index + i]; } } } internal static class DebugConsole { private static IntPtr _consoleOut; public static void Enable() { if (Settings.EnableConsole) { TryEnableConsole(); } } private static bool TryEnableConsole() { try { Kernel32.GetStdHandle(-11); if (!Kernel32.AllocConsole()) { return false; } _consoleOut = Kernel32.CreateFile("CONOUT$", 1073741824, 2, IntPtr.Zero, 3, 0, IntPtr.Zero); if (!Kernel32.SetStdHandle(-11, _consoleOut)) { return false; } StreamWriter obj = new StreamWriter(Console.OpenStandardOutput(), Encoding.Default) { AutoFlush = true }; Console.SetOut(obj); Console.SetError(obj); Kernel32.SetConsoleOutputCP(932u); Console.OutputEncoding = ConsoleEncoding.GetEncoding(932u); return true; } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred during while enabling console."); } return false; } } } namespace XUnity.AutoTranslator.Plugin.Core.Constants { public static class KnownTranslateEndpointNames { public const string GoogleTranslateV2 = "GoogleTranslateV2"; public const string GoogleTranslateLegitimate = "GoogleTranslateLegitimate"; } public static class PluginData { public const string Identifier = "gravydevsupreme.xunity.autotranslator"; public const string Name = "XUnity Auto Translator"; public const string Version = "5.6.1"; public const string Author = "gravydevsupreme"; } public static class UserAgents { public static readonly string Chrome_Win10_Latest = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36"; public static readonly string Chrome_Win7_Latest = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"; public static readonly string Firefox_Win10_Latest = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:84.0) Gecko/20100101 Firefox/84.0"; public static readonly string Edge_Win10_Latest = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66"; } } namespace XUnity.AutoTranslator.Plugin.Core.Configuration { internal static class ApplicationInformation { private static HandleRef Null = new HandleRef(null, IntPtr.Zero); public static string StartupPath { get { StringBuilder stringBuilder = new StringBuilder(260); GetModuleFileName(Null, stringBuilder, stringBuilder.Capacity); return stringBuilder.ToString(); } } [DllImport("kernel32.dll", CharSet = CharSet.Auto)] private static extern int GetModuleFileName(HandleRef hModule, StringBuilder buffer, int length); } internal static class Settings { public static string TextMeshProVersion = null; public static readonly int MaxFailuresForSameTextPerEndpoint = 3; public static readonly string TranslatorsFolder = "Translators"; public static readonly int MaxMaxCharactersPerTranslation = 2500; public static readonly string DefaultLanguage = "en"; public static readonly string DefaultFromLanguage = "ja"; public static readonly string EnglishLanguage = "en"; public static readonly string Romaji = "romaji"; public static readonly int MaxErrors = 5; public static readonly int MaxTranslationsBeforeShutdown = 8000; public static readonly int MaxUnstartedJobs = 4000; public static readonly float IncreaseBatchOperationsEvery = 30f; public static readonly int MaximumStaggers = 6; public static readonly int PreviousTextStaggerCount = 3; public static readonly int MaximumConsecutiveFramesTranslated = 90; public static readonly int MaximumConsecutiveSecondsTranslated = 60; public static bool FromLanguageUsesWhitespaceBetweenWords = false; public static bool ToLanguageUsesWhitespaceBetweenWords = false; public static string ApplicationName; public static float Timeout = 150f; public static string RedirectedResourcesPath; public static readonly int MaxImguiKeyCacheCount = 10000; public static readonly float DefaultTranslationDelay = 0.9f; public static readonly int DefaultMaxRetries = 67; public static Dictionary Replacements = new Dictionary(); public static Dictionary Preprocessors = new Dictionary(); public static Dictionary Postprocessors = new Dictionary(); public static bool SimulateError = false; public static bool SimulateDelayedError = false; public static bool InvokeEvents = true; public static Action RemakeTextData = null; public static Action SetCurText = null; public static bool IsShutdown = false; public static int TranslationCount = 0; public static int MaxAvailableBatchOperations = 50; public static readonly float MaxTranslationsQueuedPerSecond = 5f; public static readonly int MaxSecondsAboveTranslationThreshold = 30; public static readonly int TranslationQueueWatchWindow = 6; public static string ServiceEndpoint; public static string FallbackServiceEndpoint; public static string Language; public static string FromLanguage; public static string OutputFile; public static string SubstitutionFile; public static string PreprocessorsFile; public static string PostprocessorsFile; public static string TranslationDirectory; public static int MaxCharactersPerTranslation; public static bool EnableConsole; public static string AutoTranslationsFilePath; public static string SubstitutionFilePath; public static string PreprocessorsFilePath; public static string PostprocessorsFilePath; public static string TranslationsPath; public static string TexturesPath; public static string TranslatorsPath; public static bool EnableIMGUI; public static bool EnableUGUI; public static bool EnableUIElements; public static bool EnableNGUI; public static bool EnableTextMeshPro; public static bool EnableTextMesh; public static bool EnableFairyGUI; public static bool InitializeHarmonyDetourBridge; public static bool IgnoreWhitespaceInDialogue; public static int MinDialogueChars; public static int ForceSplitTextAfterCharacters; public static bool EnableMigrations; public static string MigrationsTag; public static bool EnableBatching; public static bool EnableUIResizing; public static bool UseStaticTranslations; public static string OverrideFont; public static int? OverrideFontSize; public static string OverrideFontTextMeshPro; public static string FallbackFontTextMeshPro; public static string UserAgent; public static bool DisableCertificateValidation; public static float? ResizeUILineSpacingScale; public static bool ForceUIResizing; public static string[] IgnoreTextStartingWith; public static HashSet GameLogTextPaths; public static bool TextGetterCompatibilityMode; public static TextPostProcessing RomajiPostProcessing; public static TextPostProcessing TranslationPostProcessing; public static TextPostProcessing RegexPostProcessing; public static bool ForceMonoModHooks; public static bool CacheRegexPatternResults; public static bool CacheRegexLookups; public static bool CacheWhitespaceDifferences; public static bool GenerateStaticSubstitutionTranslations; public static bool GeneratePartialTranslations; public static bool EnableTranslationScoping; public static bool EnableSilentMode; public static HashSet BlacklistedIMGUIPlugins; public static bool EnableTextPathLogging; public static bool OutputUntranslatableText; public static bool IgnoreVirtualTextSetterCallingRules; public static int MaxTextParserRecursion; public static bool HtmlEntityPreprocessing; public static bool HandleRichText; public static PersistRichTextMode PersistRichTextMode; public static bool EnableTranslationHelper; public static RedirectedResourceDetection RedirectedResourceDetectionStrategy; public static bool OutputTooLongText; public static bool TemplateAllNumberAway; public static bool ReloadTranslationsOnFileChange; public static bool DisableTextMeshProScrollInEffects; public static bool CacheParsedTranslations; public static string TextureDirectory; public static bool EnableTextureTranslation; public static bool EnableTextureDumping; public static bool EnableTextureToggling; public static bool EnableTextureScanOnSceneLoad; public static bool EnableSpriteRendererHooking; public static bool LoadUnmodifiedTextures; public static bool DetectDuplicateTextureNames; public static bool EnableLegacyTextureLoading; public static HashSet DuplicateTextureNames; public static TextureHashGenerationStrategy TextureHashGenerationStrategy; public static bool CacheTexturesInMemory; public static bool EnableSpriteHooking; public static string PreferredStoragePath; public static bool EnableDumping; public static bool EnableTextAssetRedirector; public static bool LogAllLoadedResources; public static bool CacheMetadataForAllFiles; public static float Height; public static float Width; public static HashSet EnabledTranslators; public static bool CopyToClipboard; public static int MaxClipboardCopyCharacters; public static float ClipboardDebounceTime; public static void Configure() { try { TranslatorsPath = Path.Combine(new FileInfo(typeof(Settings).Assembly.Location).Directory.FullName, TranslatorsFolder); try { try { ApplicationName = Path.GetFileNameWithoutExtension(ApplicationInformation.StartupPath); } catch (Exception) { ApplicationName = Path.GetFileNameWithoutExtension(Process.GetCurrentProcess().MainModule.FileName); } } catch (Exception ex2) { XuaLogger.AutoTranslator.Warn(ex2, "An error occurred while obtaining the path to the executable. {GameExeName} variable in configuration files will not work correctly."); ApplicationName = string.Empty; } try { XuaLogger.AutoTranslator.Debug("Screen resolution determine to be: " + Screen.width + "x" + Screen.height); } catch (Exception ex3) { XuaLogger.AutoTranslator.Warn(ex3, "An error occurred while trying to determine the game resolution."); } try { CachedProperty version = TMP_Settings_Properties.Version; if (version != null) { TextMeshProVersion = (string)version.Get((object)null); XuaLogger.AutoTranslator.Info("Version of TextMesh Pro: " + TextMeshProVersion + "."); } } catch (Exception ex4) { XuaLogger.AutoTranslator.Warn(ex4, "An error occurred while trying to determine TextMesh Pro version."); } ServiceEndpoint = PluginEnvironment.Current.Preferences.GetOrDefault("Service", "Endpoint", "GoogleTranslateV2"); FallbackServiceEndpoint = PluginEnvironment.Current.Preferences.GetOrDefault("Service", "FallbackEndpoint", string.Empty); Language = string.Intern(PluginEnvironment.Current.Preferences.GetOrDefault("General", "Language", DefaultLanguage)); FromLanguage = string.Intern(PluginEnvironment.Current.Preferences.GetOrDefault("General", "FromLanguage", DefaultFromLanguage)); TranslationDirectory = PluginEnvironment.Current.Preferences.GetOrDefault("Files", "Directory", Path.Combine("Translation", Path.Combine("{Lang}", "Text"))); OutputFile = PluginEnvironment.Current.Preferences.GetOrDefault("Files", "OutputFile", Path.Combine("Translation", Path.Combine("{Lang}", Path.Combine("Text", "_AutoGeneratedTranslations.txt")))); SubstitutionFile = PluginEnvironment.Current.Preferences.GetOrDefault("Files", "SubstitutionFile", Path.Combine("Translation", Path.Combine("{Lang}", Path.Combine("Text", "_Substitutions.txt")))); PreprocessorsFile = PluginEnvironment.Current.Preferences.GetOrDefault("Files", "PreprocessorsFile", Path.Combine("Translation", Path.Combine("{Lang}", Path.Combine("Text", "_Preprocessors.txt")))); PostprocessorsFile = PluginEnvironment.Current.Preferences.GetOrDefault("Files", "PostprocessorsFile", Path.Combine("Translation", Path.Combine("{Lang}", Path.Combine("Text", "_Postprocessors.txt")))); EnableIMGUI = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableIMGUI", defaultValue: false); EnableUGUI = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableUGUI", defaultValue: true); EnableUIElements = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableUIElements", defaultValue: true); EnableNGUI = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableNGUI", defaultValue: true); EnableTextMeshPro = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableTextMeshPro", defaultValue: true); EnableTextMesh = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableTextMesh", defaultValue: false); EnableFairyGUI = PluginEnvironment.Current.Preferences.GetOrDefault("TextFrameworks", "EnableFairyGUI", defaultValue: true); MaxCharactersPerTranslation = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "MaxCharactersPerTranslation", 200); IgnoreWhitespaceInDialogue = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "IgnoreWhitespaceInDialogue", defaultValue: true); MinDialogueChars = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "MinDialogueChars", 20); ForceSplitTextAfterCharacters = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ForceSplitTextAfterCharacters", 0); CopyToClipboard = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "CopyToClipboard", defaultValue: false); MaxClipboardCopyCharacters = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "MaxClipboardCopyCharacters", 2500); ClipboardDebounceTime = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ClipboardDebounceTime", 1.25f); EnableUIResizing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableUIResizing", defaultValue: true); EnableBatching = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableBatching", defaultValue: true); UseStaticTranslations = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "UseStaticTranslations", defaultValue: true); OverrideFont = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "OverrideFont", string.Empty); OverrideFontSize = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "OverrideFontSize", null); OverrideFontTextMeshPro = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "OverrideFontTextMeshPro", string.Empty); FallbackFontTextMeshPro = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "FallbackFontTextMeshPro", string.Empty); ResizeUILineSpacingScale = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ResizeUILineSpacingScale", null); ForceUIResizing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ForceUIResizing", defaultValue: false); IgnoreTextStartingWith = (from x in PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "IgnoreTextStartingWith", "\\u180e;")?.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries) select JsonHelper.Unescape(x)).ToArray() ?? new string[0]; TextGetterCompatibilityMode = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "TextGetterCompatibilityMode", defaultValue: false); string orDefault = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "GameLogTextPaths", string.Empty); GameLogTextPaths = ((orDefault != null) ? EnumerableExtensions.ToHashSet(orDefault.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries)) : null) ?? new HashSet(); GameLogTextPaths.RemoveWhere((string x) => !x.StartsWith("/")); RomajiPostProcessing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "RomajiPostProcessing", TextPostProcessing.ReplaceMacronWithCircumflex | TextPostProcessing.RemoveApostrophes | TextPostProcessing.ReplaceHtmlEntities); TranslationPostProcessing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "TranslationPostProcessing", TextPostProcessing.ReplaceMacronWithCircumflex | TextPostProcessing.ReplaceHtmlEntities); RegexPostProcessing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "RegexPostProcessing", TextPostProcessing.None); CacheRegexPatternResults = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "CacheRegexPatternResults", defaultValue: false); PersistRichTextMode = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "PersistRichTextMode", PersistRichTextMode.Final); CacheRegexLookups = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "CacheRegexLookups", defaultValue: false); CacheWhitespaceDifferences = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "CacheWhitespaceDifferences", defaultValue: false); GenerateStaticSubstitutionTranslations = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "GenerateStaticSubstitutionTranslations", defaultValue: false); GeneratePartialTranslations = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "GeneratePartialTranslations", defaultValue: false); EnableTranslationScoping = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableTranslationScoping", defaultValue: true); EnableSilentMode = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableSilentMode", defaultValue: true); string orDefault2 = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "BlacklistedIMGUIPlugins", string.Empty); BlacklistedIMGUIPlugins = ((orDefault2 != null) ? EnumerableExtensions.ToHashSet(from x in orDefault2.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries) select x.Trim() into x where !string.IsNullOrEmpty(x) select x, StringComparer.OrdinalIgnoreCase) : null) ?? new HashSet(StringComparer.OrdinalIgnoreCase); EnableTextPathLogging = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableTextPathLogging", defaultValue: false); OutputUntranslatableText = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "OutputUntranslatableText", defaultValue: false); IgnoreVirtualTextSetterCallingRules = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "IgnoreVirtualTextSetterCallingRules", defaultValue: false); MaxTextParserRecursion = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "MaxTextParserRecursion", 1); HtmlEntityPreprocessing = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "HtmlEntityPreprocessing", defaultValue: true); HandleRichText = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "HandleRichText", defaultValue: true); EnableTranslationHelper = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "EnableTranslationHelper", defaultValue: false); ForceMonoModHooks = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ForceMonoModHooks", defaultValue: false); InitializeHarmonyDetourBridge = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "InitializeHarmonyDetourBridge", !ClrFeatures.SupportsReflectionEmit && PluginEnvironment.Current.AllowDefaultInitializeHarmonyDetourBridge); RedirectedResourceDetectionStrategy = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "RedirectedResourceDetectionStrategy", RedirectedResourceDetection.AppendMongolianVowelSeparatorAndRemoveAll); OutputTooLongText = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "OutputTooLongText", defaultValue: false); TemplateAllNumberAway = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "TemplateAllNumberAway", defaultValue: false); ReloadTranslationsOnFileChange = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "ReloadTranslationsOnFileChange", defaultValue: false); DisableTextMeshProScrollInEffects = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "DisableTextMeshProScrollInEffects", ApplicationName.Equals("SamuraiVandalism", StringComparison.OrdinalIgnoreCase) || UnityTypes.UguiNovelText != null); CacheParsedTranslations = PluginEnvironment.Current.Preferences.GetOrDefault("Behaviour", "CacheParsedTranslations", defaultValue: false); TextureDirectory = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "TextureDirectory", Path.Combine("Translation", Path.Combine("{Lang}", "Texture"))); TexturesPath = Path.Combine(PluginEnvironment.Current.TranslationPath, TextureDirectory).Parameterize(); EnableTextureTranslation = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableTextureTranslation", Directory.Exists(TexturesPath)); EnableTextureDumping = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableTextureDumping", defaultValue: false); EnableTextureToggling = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableTextureToggling", defaultValue: false); EnableTextureScanOnSceneLoad = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableTextureScanOnSceneLoad", defaultValue: false); EnableSpriteRendererHooking = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableSpriteRendererHooking", defaultValue: false); LoadUnmodifiedTextures = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "LoadUnmodifiedTextures", defaultValue: false); DetectDuplicateTextureNames = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "DetectDuplicateTextureNames", defaultValue: false); string orDefault3 = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "DuplicateTextureNames", string.Empty); DuplicateTextureNames = ((orDefault3 != null) ? EnumerableExtensions.ToHashSet(orDefault3.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries)) : null) ?? new HashSet(); EnableLegacyTextureLoading = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableLegacyTextureLoading", defaultValue: false); TextureHashGenerationStrategy = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "TextureHashGenerationStrategy", TextureHashGenerationStrategy.FromImageName); CacheTexturesInMemory = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "CacheTexturesInMemory", defaultValue: true); EnableSpriteHooking = PluginEnvironment.Current.Preferences.GetOrDefault("Texture", "EnableSpriteHooking", defaultValue: false); PreferredStoragePath = PluginEnvironment.Current.Preferences.GetOrDefault("ResourceRedirector", "PreferredStoragePath", Path.Combine("Translation", Path.Combine("{Lang}", "RedirectedResources"))); EnableTextAssetRedirector = PluginEnvironment.Current.Preferences.GetOrDefault("ResourceRedirector", "EnableTextAssetRedirector", defaultValue: false); LogAllLoadedResources = PluginEnvironment.Current.Preferences.GetOrDefault("ResourceRedirector", "LogAllLoadedResources", defaultValue: false); EnableDumping = PluginEnvironment.Current.Preferences.GetOrDefault("ResourceRedirector", "EnableDumping", defaultValue: false); CacheMetadataForAllFiles = PluginEnvironment.Current.Preferences.GetOrDefault("ResourceRedirector", "CacheMetadataForAllFiles", defaultValue: true); if (ClipboardDebounceTime < 0.1f) { XuaLogger.AutoTranslator.Warn("'ClipboardDebounceTime' must not be lower than 0.1. Setting it to that..."); ClipboardDebounceTime = 0.1f; } if (CacheMetadataForAllFiles && EnableDumping) { XuaLogger.AutoTranslator.Warn("'EnableDumping' and 'CacheMetadataForAllFiles' cannot be enabled at the same time. Disabling 'CacheMetadataForAllFiles'..."); CacheMetadataForAllFiles = false; } RedirectedResourcesPath = StringExtensions.UseCorrectDirectorySeparators(Path.Combine(PluginEnvironment.Current.TranslationPath, PreferredStoragePath)).Parameterize(); if (MaxCharactersPerTranslation > MaxMaxCharactersPerTranslation) { IniKey obj = PluginEnvironment.Current.Preferences["Behaviour"]["MaxCharactersPerTranslation"]; int maxMaxCharactersPerTranslation = MaxMaxCharactersPerTranslation; obj.Value = maxMaxCharactersPerTranslation.ToString(CultureInfo.InvariantCulture); MaxCharactersPerTranslation = MaxMaxCharactersPerTranslation; } UserAgent = PluginEnvironment.Current.Preferences.GetOrDefault("Http", "UserAgent", string.Empty); DisableCertificateValidation = PluginEnvironment.Current.Preferences.GetOrDefault("Http", "DisableCertificateValidation", defaultValue: true); Width = PluginEnvironment.Current.Preferences.GetOrDefault("TranslationAggregator", "Width", 400f); Height = PluginEnvironment.Current.Preferences.GetOrDefault("TranslationAggregator", "Height", 100f); string orDefault4 = PluginEnvironment.Current.Preferences.GetOrDefault("TranslationAggregator", "EnabledTranslators", string.Empty); EnabledTranslators = ((orDefault4 != null) ? EnumerableExtensions.ToHashSet(orDefault4.Split(new char[1] { ';' }, StringSplitOptions.RemoveEmptyEntries)) : null) ?? new HashSet(); EnableConsole = PluginEnvironment.Current.Preferences.GetOrDefault("Debug", "EnableConsole", defaultValue: false); EnableMigrations = PluginEnvironment.Current.Preferences.GetOrDefault("Migrations", "Enable", defaultValue: true); MigrationsTag = PluginEnvironment.Current.Preferences.GetOrDefault("Migrations", "Tag", string.Empty); AutoTranslationsFilePath = Path.Combine(PluginEnvironment.Current.TranslationPath, StringExtensions.UseCorrectDirectorySeparators(OutputFile)).Parameterize(); SubstitutionFilePath = Path.Combine(PluginEnvironment.Current.TranslationPath, StringExtensions.UseCorrectDirectorySeparators(SubstitutionFile)).Parameterize(); PreprocessorsFilePath = Path.Combine(PluginEnvironment.Current.TranslationPath, StringExtensions.UseCorrectDirectorySeparators(PreprocessorsFile)).Parameterize(); PostprocessorsFilePath = Path.Combine(PluginEnvironment.Current.TranslationPath, StringExtensions.UseCorrectDirectorySeparators(PostprocessorsFile)).Parameterize(); TranslationsPath = Path.Combine(PluginEnvironment.Current.TranslationPath, StringExtensions.UseCorrectDirectorySeparators(TranslationDirectory)).Parameterize(); FromLanguageUsesWhitespaceBetweenWords = LanguageHelper.RequiresWhitespaceUponLineMerging(FromLanguage); ToLanguageUsesWhitespaceBetweenWords = LanguageHelper.RequiresWhitespaceUponLineMerging(Language); if (EnableTranslationScoping && !UnityFeatures.SupportsSceneManager) { EnableTranslationScoping = false; XuaLogger.AutoTranslator.Warn("Disabling translation scoping because the SceneManager API is not supported in this version of Unity."); } if (EnableMigrations) { Migrate(); } string migrationsTag = (PluginEnvironment.Current.Preferences["Migrations"]["Tag"].Value = "5.6.1"); MigrationsTag = migrationsTag; Save(); } catch (Exception ex5) { XuaLogger.AutoTranslator.Error(ex5, "An error occurred during configuration. Shutting plugin down."); IsShutdown = true; } } public static void AddDuplicateName(string name) { DuplicateTextureNames.Add(name); PluginEnvironment.Current.Preferences["Texture"]["DuplicateTextureNames"].Value = string.Join(";", DuplicateTextureNames.ToArray()); Save(); } public static void SetEndpoint(string id) { id = id ?? string.Empty; ServiceEndpoint = id; PluginEnvironment.Current.Preferences["Service"]["Endpoint"].Value = id; Save(); } public static void SetFallback(string id) { id = id ?? string.Empty; FallbackServiceEndpoint = id; PluginEnvironment.Current.Preferences["Service"]["FallbackEndpoint"].Value = id; Save(); } public static void SetSlientMode(bool enabled) { EnableSilentMode = enabled; PluginEnvironment.Current.Preferences["Behaviour"]["EnableSilentMode"].Value = enabled.ToString(CultureInfo.InvariantCulture); Save(); } public static void SetTranslationAggregatorBounds(float width, float height) { Width = width; Height = height; PluginEnvironment.Current.Preferences["TranslationAggregator"]["Width"].Value = Width.ToString(CultureInfo.InvariantCulture); PluginEnvironment.Current.Preferences["TranslationAggregator"]["Height"].Value = Height.ToString(CultureInfo.InvariantCulture); Save(); } public static void AddTranslator(string id) { EnabledTranslators.Add(id); PluginEnvironment.Current.Preferences["TranslationAggregator"]["EnabledTranslators"].Value = string.Join(";", EnabledTranslators.ToArray()); Save(); } public static void RemoveTranslator(string id) { EnabledTranslators.Remove(id); PluginEnvironment.Current.Preferences["TranslationAggregator"]["EnabledTranslators"].Value = string.Join(";", EnabledTranslators.ToArray()); Save(); } internal static void Save() { try { PluginEnvironment.Current.SaveConfig(); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred during while saving configuration."); } } private static void Migrate() { } } } namespace XUnity.AutoTranslator.Plugin.Core.AssetRedirection { public static class AssetLoadedContextExtensions { public static string GetPreferredFilePath(this IAssetOrResourceLoadedContext context, Object asset, string extension) { string path; if (context is AssetLoadedContext) { path = "assets"; } else { if (!(context is ResourceLoadedContext)) { throw new ArgumentException("context"); } path = "resources"; } return Path.Combine(Path.Combine(Settings.RedirectedResourcesPath, path), context.GetUniqueFileSystemAssetPath(asset)) + extension; } public static string GetPreferredFilePath(this IAssetOrResourceLoadedContext context, string parentDirectory, Object asset, string extension) { return Path.Combine(parentDirectory, context.GetUniqueFileSystemAssetPath(asset)) + extension; } public static string GetPreferredFilePathWithCustomFileName(this IAssetOrResourceLoadedContext context, Object asset, string fileName) { string path; if (context is AssetLoadedContext) { path = "assets"; } else { if (!(context is ResourceLoadedContext)) { throw new ArgumentException("context"); } path = "resources"; } string text = Path.Combine(Path.Combine(Settings.RedirectedResourcesPath, path), context.GetUniqueFileSystemAssetPath(asset)); if (fileName != null) { text = Path.Combine(text, fileName); } return text; } public static string GetPreferredFilePathWithCustomFileName(this IAssetOrResourceLoadedContext context, string parentDirectory, Object asset, string fileName) { string text = Path.Combine(parentDirectory, context.GetUniqueFileSystemAssetPath(asset)); if (fileName != null) { text = Path.Combine(text, fileName); } return text; } } public abstract class AssetLoadedHandlerBase where TAsset : Object { protected bool CheckDirectory { get; set; } [Obsolete("Use AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled to obtain whether dumping is enabled instead.")] protected bool IsDumpingEnabled => AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled; public AssetLoadedHandlerBase() { ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, 0, (Action)HandleAsset); ResourceRedirection.RegisterResourceLoadedHook((HookBehaviour)2, 0, (Action)HandleResource); } private void HandleAsset(AssetLoadedContext context) { Handle((IAssetOrResourceLoadedContext)(object)context); } private void HandleResource(ResourceLoadedContext context) { Handle((IAssetOrResourceLoadedContext)(object)context); } private void Handle(IAssetOrResourceLoadedContext context) { TAsset asset = default(TAsset); if (!ObjectExtensions.TryCastTo((object)context.Asset, ref asset) || !ShouldHandleAsset(asset, context)) { return; } string uniqueFileSystemAssetPath = context.GetUniqueFileSystemAssetPath((Object)(object)asset); string text = CalculateModificationFilePath(asset, context); if ((CheckDirectory && Directory.Exists(text)) || (!CheckDirectory && File.Exists(text))) { try { bool flag = ReplaceOrUpdateAsset(text, ref asset, context); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Replaced or updated resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Did not replace or update resource file: '" + uniqueFileSystemAssetPath + "'."); } context.Complete(flag); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while replacing or updating resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled) { try { bool flag2 = DumpAsset(text, asset, context); if (flag2) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Dumped resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Did not dump resource file: '" + uniqueFileSystemAssetPath + "'."); } context.Complete(flag2); } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while dumping resource file: '" + uniqueFileSystemAssetPath + "'."); } } if (!UnityObjectReferenceComparer.Default.Equals((object)asset, (object)context.Asset)) { context.Asset = (Object)(object)asset; } } protected abstract bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref TAsset asset, IAssetOrResourceLoadedContext context); protected abstract bool DumpAsset(string calculatedModificationPath, TAsset asset, IAssetOrResourceLoadedContext context); protected abstract string CalculateModificationFilePath(TAsset asset, IAssetOrResourceLoadedContext context); protected abstract bool ShouldHandleAsset(TAsset asset, IAssetOrResourceLoadedContext context); } public abstract class AssetLoadedHandlerBaseV2 where TAsset : Object { protected bool CheckDirectory { get; set; } public AssetLoadedHandlerBaseV2() { ResourceRedirection.RegisterAssetLoadedHook((HookBehaviour)2, 0, (Action)HandleAsset); ResourceRedirection.RegisterResourceLoadedHook((HookBehaviour)2, 0, (Action)HandleResource); } private void HandleAsset(AssetLoadedContext context) { Handle((IAssetOrResourceLoadedContext)(object)context); } private void HandleResource(ResourceLoadedContext context) { Handle((IAssetOrResourceLoadedContext)(object)context); } private void Handle(IAssetOrResourceLoadedContext context) { TAsset asset = default(TAsset); if (!ObjectExtensions.TryCastTo((object)context.Asset, ref asset) || !ShouldHandleAsset(asset, context)) { return; } string uniqueFileSystemAssetPath = context.GetUniqueFileSystemAssetPath((Object)(object)asset); string text = CalculateModificationFilePath(asset, context); if ((CheckDirectory && RedirectedDirectory.DirectoryExists(text)) || (!CheckDirectory && RedirectedDirectory.FileExists(text))) { try { bool flag = ReplaceOrUpdateAsset(text, ref asset, context); if (flag) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Replaced or updated resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Did not replace or update resource file: '" + uniqueFileSystemAssetPath + "'."); } context.Complete(flag); } catch (Exception ex) { XuaLogger.AutoTranslator.Error(ex, "An error occurred while replacing or updating resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (AutoTranslatorSettings.IsDumpingRedirectedResourcesEnabled) { try { bool flag2 = DumpAsset(text, asset, context); if (flag2) { if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Dumped resource file: '" + uniqueFileSystemAssetPath + "'."); } } else if (!Settings.EnableSilentMode) { XuaLogger.AutoTranslator.Debug("Did not dump resource file: '" + uniqueFileSystemAssetPath + "'."); } context.Complete(flag2); } catch (Exception ex2) { XuaLogger.AutoTranslator.Error(ex2, "An error occurred while dumping resource file: '" + uniqueFileSystemAssetPath + "'."); } } if (!UnityObjectReferenceComparer.Default.Equals((object)asset, (object)context.Asset)) { context.Asset = (Object)(object)asset; } } protected abstract bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref TAsset asset, IAssetOrResourceLoadedContext context); protected abstract bool DumpAsset(string calculatedModificationPath, TAsset asset, IAssetOrResourceLoadedContext context); protected abstract string CalculateModificationFilePath(TAsset asset, IAssetOrResourceLoadedContext context); protected abstract bool ShouldHandleAsset(TAsset asset, IAssetOrResourceLoadedContext context); } public static class RedirectedDirectory { private static UnzippedDirectory UnzippedDirectory; private static void Initialize() { if (UnzippedDirectory == null) { UnzippedDirectory = new UnzippedDirectory(Settings.RedirectedResourcesPath, Settings.CacheMetadataForAllFiles); } } internal static void Uninitialize() { if (UnzippedDirectory != null) { UnzippedDirectory.Dispose(); UnzippedDirectory = null; } } public static IEnumerable GetFilesInDirectory(string path, params string[] extensions) { Initialize(); return UnzippedDirectory.GetFiles(path, extensions); } public static IEnumerable GetFile(string path) { Initialize(); return UnzippedDirectory.GetFile(path); } public static bool DirectoryExists(string path) { Initialize(); return UnzippedDirectory.DirectoryExists(path); } public static bool FileExists(string path) { Initialize(); return UnzippedDirectory.FileExists(path); } } public class RedirectedResource { private readonly Func _streamFactory; public bool IsZipped { get; } public string ContainerFile { get; } public string FullName { get; } internal RedirectedResource(Func streamFactory, string containerFile, string fullName) { _streamFactory = streamFactory; IsZipped = containerFile != null; ContainerFile = containerFile; FullName = fullName; } internal RedirectedResource(string fullName) { FullName = fullName; _streamFactory = () => File.OpenRead(FullName); } public Stream OpenStream() { return _streamFactory(); } } public class TextAndEncoding { public string Text { get; } public byte[] Bytes { get; } public Encoding Encoding { get; } public TextAndEncoding(string text, Encoding encoding) { Text = text; Encoding = encoding; } public TextAndEncoding(byte[] bytes, Encoding encoding) { Bytes = bytes; Encoding = encoding; } public TextAndEncoding(byte[] bytes) { Bytes = bytes; } } internal class TextAssetExtensionData { private string _text; private byte[] _data; public Encoding Encoding { get; set; } public byte[] Data { get { if (_data == null && _text != null) { MemoryStream memoryStream = new MemoryStream(); using StreamWriter streamWriter = new StreamWriter(memoryStream, Encoding ?? Encoding.UTF8); streamWriter.Write(_text); streamWriter.Flush(); _data = memoryStream.ToArray(); } return _data; } set { _data = value; } } public string Text { get { if (_text == null && _data != null) { using StreamReader streamReader = new StreamReader(new MemoryStream(_data), Encoding ?? Encoding.UTF8); _text = streamReader.ReadToEnd(); } return _text; } set { _text = value; } } } internal class TextAssetLoadedHandler : AssetLoadedHandlerBaseV2 { public TextAssetLoadedHandler() { HooksSetup.InstallTextAssetHooks(); } protected override string CalculateModificationFilePath(TextAsset asset, IAssetOrResourceLoadedContext context) { return context.GetPreferredFilePath((Object)(object)asset, ".txt"); } protected override bool DumpAsset(string calculatedModificationPath, TextAsset asset, IAssetOrResourceLoadedContext context) { Directory.CreateDirectory(new FileInfo(calculatedModificationPath).Directory.FullName); byte[] bytes = asset.bytes; if (bytes != null) { File.WriteAllBytes(calculatedModificationPath, bytes); return true; } string text = asset.text; if (text != null) { File.WriteAllText(calculatedModificationPath, text, Encoding.UTF8); return true; } return false; } protected override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref TextAsset asset, IAssetOrResourceLoadedContext context) { List list = RedirectedDirectory.GetFile(calculatedModificationPath).ToList(); if (list.Count == 0) { return false; } if (list.Count > 1) { XuaLogger.AutoTranslator.Warn("Found more than one resource file in the same path: " + calculatedModificationPath); } RedirectedResource redirectedResource = list.FirstOrDefault(); if (redirectedResource != null) { using (Stream stream = redirectedResource.OpenStream()) { byte[] data = StreamExtensions.ReadFully(stream, (int)stream.Length); TextAssetExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData((object)asset); orCreateExtensionData.Encoding = Encoding.UTF8; orCreateExtensionData.Data = data; return true; } } return false; } protected override bool ShouldHandleAsset(TextAsset asset, IAssetOrResourceLoadedContext context) { return !context.HasReferenceBeenRedirectedBefore((Object)(object)asset); } } public abstract class TextAssetLoadedHandlerBase : AssetLoadedHandlerBaseV2 { public TextAssetLoadedHandlerBase() { HooksSetup.InstallTextAssetHooks(); } public abstract TextAndEncoding TranslateTextAsset(string calculatedModificationPath, TextAsset asset, IAssetOrResourceLoadedContext context); protected sealed override bool ReplaceOrUpdateAsset(string calculatedModificationPath, ref TextAsset asset, IAssetOrResourceLoadedContext context) { TextAndEncoding textAndEncoding = TranslateTextAsset(calculatedModificationPath, asset, context); if (textAndEncoding != null) { TextAssetExtensionData orCreateExtensionData = ExtensionDataHelper.GetOrCreateExtensionData((object)asset); orCreateExtensionData.Encoding = textAndEncoding.Encoding; orCreateExtensionData.Text = textAndEncoding.Text; orCreateExtensionData.Data = textAndEncoding.Bytes; return true; } return false; } } internal class UnzippedDirectory : IDisposable { private class FileEntry { private string _fullPath; public string FileName { get; } public string ContainerFile { get; } public ZipFile ZipFile { get; } public ZipEntry ZipEntry { get; } public bool IsZipped => ContainerFile != null; public string FullPath { get { if (_fullPath == null) { if (ContainerFile != null) { _fullPath = Path.Combine(ContainerFile, FileName); } else { _fullPath = FileName; } } return _fullPath; } } public FileEntry(string fileName, string containerFile, ZipFile zipFile, ZipEntry zipEntry) { FileName = fileName; ContainerFile = containerFile; ZipFile = zipFile; ZipEntry = zipEntry; } public FileEntry(string fileName) { FileName = fileName; } } private class DirectoryEntry { private Dictionary _directories = new Dictionary(StringComparer.OrdinalIgnoreCase); private Dictionary> _files = new Dictionary>(StringComparer.OrdinalIgnoreCase); public DirectoryEntry GetOrCreateDirectory(string name) { if (!_directories.TryGetValue(name, out var value)) { value = new DirectoryEntry(); _directories.Add(name, value); } return value; } public DirectoryEntry GetDirectory(string name) { _directories.TryGetValue(name, out var value); return value; } public void AddFile(string name, FileEntry entry) { if (!_files.TryGetValue(name, out var value)) { value = new List(); _files.Add(name, value); } value.Add(entry); } public List GetFiles(string fullPath, string[] extensions, bool findAllByExtensionInLastDirectory) { List list = new List(); string[] parts = fullPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries); FillEntries(parts, 0, extensions, findAllByExtensionInLastDirectory, list); return list; } public bool DirectoryExists(string fullPath) { DirectoryEntry directoryEntry = this; string[] array = fullPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries); foreach (string name in array) { directoryEntry = directoryEntry.GetDirectory(name); if (directoryEntry == null) { return false; } } return true; } public bool FileExists(string fullPath) { DirectoryEntry directoryEntry = this; string[] array = fullPath.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i]; if (i == array.Length - 1) { return directoryEntry._files.ContainsKey(text); } directoryEntry = directoryEntry.GetDirectory(text); if (directoryEntry == null) { return false; } } return true; } private void FillEntries(string[] parts, int index, string[] extensions, bool findAllByExtensionInLastDirectory, List entries) { if (index < parts.Length) { string key = parts[index]; DirectoryEntry value2; if (!findAllByExtensionInLastDirectory && index == parts.Length - 1) { if (_files.TryGetValue(key, out var value)) { entries.AddRange(value); } } else if (_directories.TryGetValue(key, out value2)) { value2.FillEntries(parts, index + 1, extensions, findAllByExtensionInLastDirectory, entries); } } else { if (!findAllByExtensionInLastDirectory) { return; } if (extensions == null || extensions.Length == 0) { foreach (KeyValuePair> file in _files) { entries.AddRange(file.Value); } return; } foreach (KeyValuePair> file2 in _files) { string fileName = file2.Key; if (extensions.Any((string x) => fileName.EndsWith(x, StringComparison.OrdinalIgnoreCase))) { entries.AddRange(file2.Value); } } } } } [CompilerGenerated] private sealed class <>c__DisplayClass7_0 { public string file; internal bool b__0(string x) { return file.EndsWith(x, StringComparison.OrdinalIgnoreCase); } } [CompilerGenerated] private sealed class <>c__DisplayClass7_1 { public FileEntry entry; internal Stream b__4() { return entry.ZipFile.GetInputStream(entry.ZipEntry); } } [CompilerGenerated] private sealed class <>c__DisplayClass8_0 { public FileEntry entry; internal Stream b__3() { return entry.ZipFile.GetInputStream(entry.ZipEntry); } } [CompilerGenerated] private sealed class d__8 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private RedirectedResource <>2__current; private int <>l__initialThreadId; public UnzippedDirectory <>4__this; private string path; public string <>3__path; private IEnumerator <>7__wrap1; RedirectedResource IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__8(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 2) <= 1u) { try { } finally { <>m__Finally1(); } } <>7__wrap1 = null; <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; UnzippedDirectory unzippedDirectory = <>4__this; IOrderedEnumerable orderedEnumerable; switch (num) { default: return false; case 0: <>1__state = -1; if (!unzippedDirectory._cacheNormalFiles && File.Exists(path)) { <>2__current = new RedirectedResource(path); <>1__state = 1; return true; } goto IL_006d; case 1: <>1__state = -1; goto IL_006d; case 2: <>1__state = -3; goto IL_01f2; case 3: { <>1__state = -3; goto IL_01f2; } IL_01f2: if (<>7__wrap1.MoveNext()) { <>c__DisplayClass8_0 CS$<>8__locals0 = new <>c__DisplayClass8_0 { entry = <>7__wrap1.Current }; if (CS$<>8__locals0.entry.IsZipped) { <>2__current = new RedirectedResource(() => CS$<>8__locals0.entry.ZipFile.GetInputStream(CS$<>8__locals0.entry.ZipEntry), CS$<>8__locals0.entry.ContainerFile, CS$<>8__locals0.entry.FullPath); <>1__state = 2; return true; } <>2__current = new RedirectedResource(CS$<>8__locals0.entry.FileName); <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap1 = null; break; IL_006d: if (unzippedDirectory._rootDirectory == null) { break; } path = path.ToLowerInvariant(); if (!Path.IsPathRooted(path)) { path = Path.Combine(_loweredCurrentDirectory, path); } path = StringExtensions.MakeRelativePath(path, unzippedDirectory._root); orderedEnumerable = from x in unzippedDirectory._rootDirectory.GetFiles(path, null, findAllByExtensionInLastDirectory: false) orderby x.IsZipped, x.ContainerFile, x.FullPath select x; <>7__wrap1 = orderedEnumerable.GetEnumerator(); <>1__state = -3; goto IL_01f2; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>7__wrap1 != null) { <>7__wrap1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__8 d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__8(0) { <>4__this = <>4__this }; } d__.path = <>3__path; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } [CompilerGenerated] private sealed class d__7 : IEnumerable, IEnumerable, IEnumerator, IDisposable, IEnumerator { private int <>1__state; private RedirectedResource <>2__current; private int <>l__initialThreadId; public UnzippedDirectory <>4__this; private string path; public string <>3__path; private string[] extensions; public string[] <>3__extensions; private bool 5__2; private string[] <>7__wrap2; private int <>7__wrap3; private List.Enumerator <>7__wrap4; RedirectedResource IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public d__7(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || (uint)(num - 2) <= 1u) { try { } finally { <>m__Finally1(); } } <>7__wrap2 = null; <>7__wrap4 = default(List.Enumerator); <>1__state = -2; } private bool MoveNext() { try { int num = <>1__state; UnzippedDirectory unzippedDirectory = <>4__this; List list; switch (num) { default: return false; case 0: <>1__state = -1; if (!unzippedDirectory._cacheNormalFiles && Directory.Exists(path)) { 5__2 = extensions == null || extensions.Length == 0; string[] files = Directory.GetFiles(path, "*", SearchOption.TopDirectoryOnly); <>7__wrap2 = files; <>7__wrap3 = 0; goto IL_00fc; } goto IL_0116; case 1: <>1__state = -1; goto IL_00ee; case 2: <>1__state = -3; goto IL_02a2; case 3: { <>1__state = -3; goto IL_02a2; } IL_00fc: if (<>7__wrap3 < <>7__wrap2.Length) { <>c__DisplayClass7_0 CS$<>8__locals0 = new <>c__DisplayClass7_0 { file = <>7__wrap2[<>7__wrap3] }; if (5__2 || extensions.Any((string x) => CS$<>8__locals0.file.EndsWith(x, StringComparison.OrdinalIgnoreCase))) { <>2__current = new RedirectedResource(CS$<>8__locals0.file); <>1__state = 1; return true; } goto IL_00ee; } <>7__wrap2 = null; goto IL_0116; IL_02a2: if (<>7__wrap4.MoveNext()) { <>c__DisplayClass7_1 CS$<>8__locals1 = new <>c__DisplayClass7_1 { entry = <>7__wrap4.Current }; if (CS$<>8__locals1.entry.IsZipped) { <>2__current = new RedirectedResource(() => CS$<>8__locals1.entry.ZipFile.GetInputStream(CS$<>8__locals1.entry.ZipEntry), CS$<>8__locals1.entry.ContainerFile, CS$<>8__locals1.entry.FullPath); <>1__state = 2; return true; } <>2__current = new RedirectedResource(CS$<>8__locals1.entry.FileName); <>1__state = 3; return true; } <>m__Finally1(); <>7__wrap4 = default(List.Enumerator); break; IL_00ee: <>7__wrap3++; goto IL_00fc; IL_0116: if (unzippedDirectory._rootDirectory == null) { break; } path = path.ToLowerInvariant(); if (!Path.IsPathRooted(path)) { path = Path.Combine(_loweredCurrentDirectory, path); } path = StringExtensions.MakeRelativePath(path, unzippedDirectory._root); list = (from x in unzippedDirectory._rootDirectory.GetFiles(path, null, findAllByExtensionInLastDirectory: true) orderby x.IsZipped, x.ContainerFile, x.FullPath select x).ToList(); <>7__wrap4 = list.GetEnumerator(); <>1__state = -3; goto IL_02a2; } return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap4).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { d__7 d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; d__ = this; } else { d__ = new d__7(0) { <>4__this = <>4__this }; } d__.path = <>3__path; d__.extensions = <>3__extensions; return d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable)this).GetEnumerator(); } } private static readonly char[] PathSeparators = new char[2] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }; private static readonly string _loweredCurrentDirectory = Paths.GameRoot.ToLowerInvariant(); private readonly string _root; private readonly bool _cacheNormalFiles; private DirectoryEntry _rootDirectory; private List _allZipFiles; private bool disposedValue; public UnzippedDirectory(string root, bool cacheNormalFiles) { _cacheNormalFiles = cacheNormalFiles; _allZipFiles = new List(); Directory.CreateDirectory(root); if (Path.IsPathRooted(root)) { _root = root.ToLowerInvariant(); } else { _root = Path.Combine(_loweredCurrentDirectory, root.ToLowerInvariant()); } Initialize(); } public IEnumerable GetFiles(string path, params string[] extensions) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__7(-2) { <>4__this = this, <>3__path = path, <>3__extensions = extensions }; } public IEnumerable GetFile(string path) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new d__8(-2) { <>4__this = this, <>3__path = path }; } public bool DirectoryExists(string path) { string path2 = path; bool flag = false; if (_rootDirectory != null) { path = path.ToLowerInvariant(); if (!Path.IsPathRooted(path)) { path = Path.Combine(_loweredCurrentDirectory, path); } path = StringExtensions.MakeRelativePath(path, _root); flag = _rootDirectory.DirectoryExists(path); } if (!flag) { if (!_cacheNormalFiles) { return Directory.Exists(path2); } return false; } return true; } public bool FileExists(string path) { string path2 = path; bool flag = false; if (_rootDirectory != null) { path = path.ToLowerInvariant(); if (!Path.IsPathRooted(path)) { path = Path.Combine(_loweredCurrentDirectory, path); } path = StringExtensions.MakeRelativePath(path, _root); flag = _rootDirectory.FileExists(path); } if (!flag) { if (!_cacheNormalFiles) { return File.Exists(path2); } return false; } return true; } private void Initialize() { if (!Directory.Exists(_root)) { return; } string[] files = Directory.GetFiles(_root, "*", SearchOption.AllDirectories); if (files.Length != 0) { _rootDirectory = new DirectoryEntry(); } string[] array = files; foreach (string text in array) { bool flag = text.EndsWith(".zip", StringComparison.OrdinalIgnoreCase); if (!flag && (!_cacheNormalFiles || flag)) { continue; } DirectoryEntry directoryEntry = _rootDirectory; string[] array2 = StringExtensions.MakeRelativePath(text.ToLowerInvariant(), _root).Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries); for (int j = 0; j < array2.Length; j++) { string text2 = array2[j]; if (j == array2.Length - 1) { if (text2.EndsWith(".zip", StringComparison.OrdinalIgnoreCase)) { DirectoryEntry directoryEntry2 = directoryEntry; ZipFile zipFile = new ZipFile(text); _allZipFiles.Add(zipFile); foreach (ZipEntry item in zipFile) { directoryEntry = directoryEntry2; string text3 = StringExtensions.UseCorrectDirectorySeparators(item.Name).ToLowerInvariant(); string[] array3 = text3.Split(PathSeparators, StringSplitOptions.RemoveEmptyEntries); for (int k = 0; k < array3.Length; k++) { string name = array3[k]; if (k == array3.Length - 1) { if (item.IsFile) { directoryEntry.AddFile(name, new FileEntry(text3, text, zipFile, item)); } else { directoryEntry = directoryEntry.GetOrCreateDirectory(name); } } else { directoryEntry = directoryEntry.GetOrCreateDirectory(name); } } } } else { directoryEntry.AddFile(text2, new FileEntry(text)); } } else { directoryEntry = directoryEntry.GetOrCreateDirectory(text2); } } } } protected virtual void Dispose(bool disposing) { if (disposedValue) { return; } foreach (ZipFile allZipFile in _allZipFiles) { allZipFile.Close(); } disposedValue = true; } public void Dispose() { Dispose(disposing: true); } } } [CompilerGenerated] internal sealed class <02fa20f3-fb99-4d1e-a6ff-af799eea2c65> { [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 3)] internal struct __StaticArrayInitTypeSize=3 { } [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 6)] internal struct __StaticArrayInitTypeSize=6 { } internal static readonly __StaticArrayInitTypeSize=6 BB35CC750AF41AA15C93F9B34042FDBFBF54F859CBCD30EE57D6B58194F0CD25/* Not supported: data(0A 00 20 00 00 30) */; internal static readonly __StaticArrayInitTypeSize=3 F1945CD6C19E56B3C1C78943EF5EC18116907A4CA1EFC40A57D48AB1DB7ADFC5/* Not supported: data(EF BB BF) */; } namespace ICSharpCode.SharpZipLib.Zip.Compression.Streams { internal class InflaterInputBuffer { private int rawLength; private byte[] rawData; private int clearTextLength; private byte[] clearText; private byte[] internalClearText; private int available; private ICryptoTransform cryptoTransform; private Stream inputStream; public int RawLength => rawLength; public byte[] RawData => rawData; public int ClearTextLength => clearTextLength; public byte[] ClearText => clearText; public int Available { get { return available; } set { available = value; } } public ICryptoTransform CryptoTransform { set { cryptoTransform = value; if (cryptoTransform != null) { if (rawData == clearText) { if (internalClearText == null) { internalClearText = new byte[4096]; } clearText = internalClearText; } clearTextLength = rawLength; if (available > 0) { cryptoTransform.TransformBlock(rawData, rawLength - available, available, clearText, rawLength - available); } } else { clearText = rawData; clearTextLength = rawLength; } } } public InflaterInputBuffer(Stream stream) { inputStream = stream; rawData = new byte[4096]; clearText = rawData; } public void SetInflaterInput(Inflater inflater) { if (available > 0) { inflater.SetInput(clearText, clearTextLength - available, available); available = 0; } } public void Fill() { rawLength = 0; int num = rawData.Length; while (num > 0) { int num2 = inputStream.Read(rawData, rawLength, num); if (num2 <= 0) { if (rawLength == 0) { throw new SharpZipBaseException("Unexpected EOF"); } break; } rawLength += num2; num -= num2; } if (cryptoTransform != null) { clearTextLength = cryptoTransform.TransformBlock(rawData, 0, rawLength, clearText, 0); } else { clearTextLength = rawLength; } available = clearTextLength; } public int ReadRawBuffer(byte[] buffer) { return ReadRawBuffer(buffer, 0, buffer.Length); } public int ReadRawBuffer(byte[] outBuffer, int offset, int length) { if (length <= 0) { throw new ArgumentOutOfRangeException("length"); } int num = offset; int num2 = length; while (num2 > 0) { if (available <= 0) { Fill(); if (available <= 0) { return 0; } } int num3 = Math.Min(num2, available); Array.Copy(rawData, rawLength - available, outBuffer, num, num3); num += num3; num2 -= num3; available -= num3; } return length; } public int ReadClearTextBuffer(byte[] outBuffer, int offset, int length) { if (length <= 0) { throw new ArgumentOutOfRangeException("length"); } int num = offset; int num2 = length; while (num2 > 0) { if (available <= 0) { Fill(); if (available <= 0) { return 0; } } int num3 = Math.Min(num2, available); Array.Copy(clearText, clearTextLength - available, outBuffer, num, num3); num += num3; num2 -= num3; available -= num3; } return length; } public int ReadLeByte() { if (available <= 0) { Fill(); if (available <= 0) { throw new ZipException("EOF in header"); } } byte result = (byte)(rawData[rawLength - available] & 0xFFu); available--; return result; } public int ReadLeShort() { return ReadLeByte() | (ReadLeByte() << 8); } public int ReadLeInt() { return ReadLeShort() | (ReadLeShort() << 16); } public long ReadLeLong() { return ReadLeInt() | (ReadLeInt() << 0); } } internal class InflaterInputStream : Stream { protected Inflater inf; protected InflaterInputBuffer inputBuffer; protected Stream baseInputStream; protected long csize; private bool isClosed; private bool isStreamOwner = true; public bool IsStreamOwner { get { return isStreamOwner; } set { isStreamOwner = value; } } public override bool CanRead => baseInputStream.CanRead; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => inputBuffer.RawLength; public override long Position { get { return baseInputStream.Position; } set { throw new NotSupportedException("InflaterInputStream Position not supported"); } } public virtual int Available => (!inf.IsFinished) ? 1 : 0; public InflaterInputStream(Stream baseInputStream) : this(baseInputStream, new Inflater(), 4096) { } public InflaterInputStream(Stream baseInputStream, Inflater inf) : this(baseInputStream, inf, 4096) { } public InflaterInputStream(Stream baseInputStream, Inflater inflater, int bufferSize) { if (baseInputStream == null) { throw new ArgumentNullException("InflaterInputStream baseInputStream is null"); } if (inflater == null) { throw new ArgumentNullException("InflaterInputStream Inflater is null"); } if (bufferSize <= 0) { throw new ArgumentOutOfRangeException("bufferSize"); } this.baseInputStream = baseInputStream; inf = inflater; inputBuffer = new InflaterInputBuffer(baseInputStream); } public override void Flush() { baseInputStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("Seek not supported"); } public override void SetLength(long val) { throw new NotSupportedException("InflaterInputStream SetLength not supported"); } public override void Write(byte[] array, int offset, int count) { throw new NotSupportedException("InflaterInputStream Write not supported"); } public override void WriteByte(byte val) { throw new NotSupportedException("InflaterInputStream WriteByte not supported"); } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new NotSupportedException("InflaterInputStream BeginWrite not supported"); } public override void Close() { if (!isClosed) { isClosed = true; if (isStreamOwner) { baseInputStream.Close(); } } } protected void Fill() { inputBuffer.Fill(); inputBuffer.SetInflaterInput(inf); } public override int Read(byte[] b, int off, int len) { while (true) { int num; try { num = inf.Inflate(b, off, len); } catch (Exception ex) { throw new SharpZipBaseException(ex.ToString()); } if (num > 0) { return num; } if (inf.IsNeedingDictionary) { throw new SharpZipBaseException("Need a dictionary"); } if (inf.IsFinished) { return 0; } if (!inf.IsNeedingInput) { break; } Fill(); } throw new InvalidOperationException("Don't know what to do"); } public long Skip(long n) { if (n <= 0) { throw new ArgumentOutOfRangeException("n"); } if (baseInputStream.CanSeek) { baseInputStream.Seek(n, SeekOrigin.Current); return n; } int num = 2048; if (n < num) { num = (int)n; } byte[] array = new byte[num]; return baseInputStream.Read(array, 0, array.Length); } protected void StopDecrypting() { inputBuffer.CryptoTransform = null; } } internal class DeflaterOutputStream : Stream { protected byte[] buf; protected Deflater def; protected Stream baseOutputStream; private bool isClosed; private bool isStreamOwner = true; private string password; private uint[] keys; public bool IsStreamOwner { get { return isStreamOwner; } set { isStreamOwner = value; } } public bool CanPatchEntries => baseOutputStream.CanSeek; public override bool CanRead => baseOutputStream.CanRead; public override bool CanSeek => false; public override bool CanWrite => baseOutputStream.CanWrite; public override long Length => baseOutputStream.Length; public override long Position { get { return baseOutputStream.Position; } set { throw new NotSupportedException("DefalterOutputStream Position not supported"); } } public string Password { get { return password; } set { if (value != null && value.Length == 0) { password = null; } else { password = value; } } } public DeflaterOutputStream(Stream baseOutputStream) : this(baseOutputStream, new Deflater(), 512) { } public DeflaterOutputStream(Stream baseOutputStream, Deflater defl) : this(baseOutputStream, defl, 512) { } public DeflaterOutputStream(Stream baseOutputStream, Deflater deflater, int bufsize) { if (!baseOutputStream.CanWrite) { throw new ArgumentException("baseOutputStream", "must support writing"); } if (deflater == null) { throw new ArgumentNullException("deflater"); } if (bufsize <= 0) { throw new ArgumentOutOfRangeException("bufsize"); } this.baseOutputStream = baseOutputStream; buf = new byte[bufsize]; def = deflater; } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("DeflaterOutputStream Seek not supported"); } public override void SetLength(long val) { throw new NotSupportedException("DeflaterOutputStream SetLength not supported"); } public override int ReadByte() { throw new NotSupportedException("DeflaterOutputStream ReadByte not supported"); } public override int Read(byte[] b, int off, int len) { throw new NotSupportedException("DeflaterOutputStream Read not supported"); } public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new NotSupportedException("DeflaterOutputStream BeginRead not currently supported"); } public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state) { throw new NotSupportedException("DeflaterOutputStream BeginWrite not currently supported"); } protected void Deflate() { while (!def.IsNeedingInput) { int num = def.Deflate(buf, 0, buf.Length); if (num <= 0) { break; } if (keys != null) { EncryptBlock(buf, 0, num); } baseOutputStream.Write(buf, 0, num); } if (!def.IsNeedingInput) { throw new SharpZipBaseException("DeflaterOutputStream can't deflate all input?"); } } public override void Flush() { def.Flush(); Deflate(); baseOutputStream.Flush(); } public virtual void Finish() { def.Finish(); while (!def.IsFinished) { int num = def.Deflate(buf, 0, buf.Length); if (num <= 0) { break; } if (keys != null) { EncryptBlock(buf, 0, num); } baseOutputStream.Write(buf, 0, num); } if (!def.IsFinished) { throw new SharpZipBaseException("Can't deflate all input?"); } baseOutputStream.Flush(); keys = null; } public override void Close() { if (!isClosed) { isClosed = true; Finish(); if (isStreamOwner) { baseOutputStream.Close(); } } } public override void WriteByte(byte bval) { Write(new byte[1] { bval }, 0, 1); } public override void Write(byte[] buf, int off, int len) { def.SetInput(buf, off, len); Deflate(); } protected byte EncryptByte() { uint num = (keys[2] & 0xFFFFu) | 2u; return (byte)(num * (num ^ 1) >> 8); } protected void EncryptBlock(byte[] buffer, int offset, int length) { for (int i = offset; i < offset + length; i++) { byte ch = buffer[i]; buffer[i] ^= EncryptByte(); UpdateKeys(ch); } } protected void InitializePassword(string password) { keys = new uint[3] { 305419896u, 591751049u, 878082192u }; for (int i = 0; i < password.Length; i++) { UpdateKeys((byte)password[i]); } } protected void UpdateKeys(byte ch) { keys[0] = Crc32.ComputeCrc32(keys[0], ch); keys[1] = keys[1] + (byte)keys[0]; keys[1] = keys[1] * 134775813 + 1; keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24)); } } internal class StreamManipulator { private byte[] window; private int window_start; private int window_end; private uint buffer; private int bits_in_buffer; public int AvailableBits => bits_in_buffer; public int AvailableBytes => window_end - window_start + (bits_in_buffer >> 3); public bool IsNeedingInput => window_start == window_end; public int PeekBits(int n) { if (bits_in_buffer < n) { if (window_start == window_end) { return -1; } buffer |= (uint)(((window[window_start++] & 0xFF) | ((window[window_start++] & 0xFF) << 8)) << bits_in_buffer); bits_in_buffer += 16; } return (int)(buffer & ((1 << n) - 1)); } public void DropBits(int n) { buffer >>= n; bits_in_buffer -= n; } public int GetBits(int n) { int num = PeekBits(n); if (num >= 0) { DropBits(n); } return num; } public void SkipToByteBoundary() { buffer >>= bits_in_buffer & 7; bits_in_buffer &= -8; } public int CopyBytes(byte[] output, int offset, int length) { if (length < 0) { throw new ArgumentOutOfRangeException("length"); } if (((uint)bits_in_buffer & 7u) != 0) { throw new InvalidOperationException("Bit buffer is not byte aligned!"); } int num = 0; while (bits_in_buffer > 0 && length > 0) { output[offset++] = (byte)buffer; buffer >>= 8; bits_in_buffer -= 8; length--; num++; } if (length == 0) { return num; } int num2 = window_end - window_start; if (length > num2) { length = num2; } Array.Copy(window, window_start, output, offset, length); window_start += length; if (((uint)(window_start - window_end) & (true ? 1u : 0u)) != 0) { buffer = window[window_start++] & 0xFFu; bits_in_buffer = 8; } return num + length; } public void Reset() { bits_in_buffer = 0; window_end = 0; buffer = (uint)(window_start = 0); } public void SetInput(byte[] buf, int off, int len) { if (window_start < window_end) { throw new InvalidOperationException("Old input was not completely processed"); } int num = off + len; if (0 > off || off > num || num > buf.Length) { throw new ArgumentOutOfRangeException(); } if (((uint)len & (true ? 1u : 0u)) != 0) { buffer |= (uint)((buf[off++] & 0xFF) << bits_in_buffer); bits_in_buffer += 8; } window = buf; window_start = off; window_end = num; } } internal class OutputWindow { private static int WINDOW_SIZE = 32768; private static int WINDOW_MASK = WINDOW_SIZE - 1; private byte[] window = new byte[WINDOW_SIZE]; private int windowEnd; private int windowFilled; public void Write(int abyte) { if (windowFilled++ == WINDOW_SIZE) { throw new InvalidOperationException("Window full"); } window[windowEnd++] = (byte)abyte; windowEnd &= WINDOW_MASK; } private void SlowRepeat(int repStart, int len, int dist) { while (len-- > 0) { window[windowEnd++] = window[repStart++]; windowEnd &= WINDOW_MASK; repStart &= WINDOW_MASK; } } public void Repeat(int len, int dist) { if ((windowFilled += len) > WINDOW_SIZE) { throw new InvalidOperationException("Window full"); } int num = (windowEnd - dist) & WINDOW_MASK; int num2 = WINDOW_SIZE - len; if (num <= num2 && windowEnd < num2) { if (len <= dist) { Array.Copy(window, num, window, windowEnd, len); windowEnd += len; } else { while (len-- > 0) { window[windowEnd++] = window[num++]; } } } else { SlowRepeat(num, len, dist); } } public int CopyStored(StreamManipulator input, int len) { len = Math.Min(Math.Min(len, WINDOW_SIZE - windowFilled), input.AvailableBytes); int num = WINDOW_SIZE - windowEnd; int num2; if (len > num) { num2 = input.CopyBytes(window, windowEnd, num); if (num2 == num) { num2 += input.CopyBytes(window, 0, len - num); } } else { num2 = input.CopyBytes(window, windowEnd, len); } windowEnd = (windowEnd + num2) & WINDOW_MASK; windowFilled += num2; return num2; } public void CopyDict(byte[] dict, int offset, int len) { if (windowFilled > 0) { throw new InvalidOperationException(); } if (len > WINDOW_SIZE) { offset += len - WINDOW_SIZE; len = WINDOW_SIZE; } Array.Copy(dict, offset, window, 0, len); windowEnd = len & WINDOW_MASK; } public int GetFreeSpace() { return WINDOW_SIZE - windowFilled; } public int GetAvailable() { return windowFilled; } public int CopyOutput(byte[] output, int offset, int len) { int num = windowEnd; if (len > windowFilled) { len = windowFilled; } else { num = (windowEnd - windowFilled + len) & WINDOW_MASK; } int num2 = len; int num3 = len - num; if (num3 > 0) { Array.Copy(window, WINDOW_SIZE - num3, output, offset, num3); offset += num3; len = num; } Array.Copy(window, num - len, output, offset, len); windowFilled -= num2; if (windowFilled < 0) { throw new InvalidOperationException(); } return num2; } public void Reset() { windowEnd = 0; windowFilled = 0; } } } namespace ICSharpCode.SharpZipLib.Zip.Compression { internal class InflaterHuffmanTree { private static int MAX_BITLEN; private short[] tree; public static InflaterHuffmanTree defLitLenTree; public static InflaterHuffmanTree defDistTree; public InflaterHuffmanTree(byte[] codeLengths) { BuildTree(codeLengths); } static InflaterHuffmanTree() { MAX_BITLEN = 15; try { byte[] array = new byte[288]; int num = 0; while (num < 144) { array[num++] = 8; } while (num < 256) { array[num++] = 9; } while (num < 280) { array[num++] = 7; } while (num < 288) { array[num++] = 8; } defLitLenTree = new InflaterHuffmanTree(array); array = new byte[32]; num = 0; while (num < 32) { array[num++] = 5; } defDistTree = new InflaterHuffmanTree(array); } catch (Exception) { throw new SharpZipBaseException("InflaterHuffmanTree: static tree length illegal"); } } private void BuildTree(byte[] codeLengths) { int[] array = new int[MAX_BITLEN + 1]; int[] array2 = new int[MAX_BITLEN + 1]; foreach (int num in codeLengths) { if (num > 0) { array[num]++; } } int num2 = 0; int num3 = 512; for (int j = 1; j <= MAX_BITLEN; j++) { array2[j] = num2; num2 += array[j] << 16 - j; if (j >= 10) { int num4 = array2[j] & 0x1FF80; int num5 = num2 & 0x1FF80; num3 += num5 - num4 >> ((16 - j) & 0x1F); } } tree = new short[num3]; int num6 = 512; for (int num7 = MAX_BITLEN; num7 >= 10; num7--) { int num8 = num2 & 0x1FF80; num2 -= array[num7] << 16 - num7; int num9 = num2 & 0x1FF80; for (int k = num9; k < num8; k += 128) { tree[DeflaterHuffman.BitReverse(k)] = (short)((-num6 << 4) | num7); num6 += 1 << num7 - 9; } } for (int l = 0; l < codeLengths.Length; l++) { int num10 = codeLengths[l]; if (num10 == 0) { continue; } num2 = array2[num10]; int num11 = DeflaterHuffman.BitReverse(num2); if (num10 <= 9) { do { tree[num11] = (short)((l << 4) | num10); num11 += 1 << (num10 & 0x1F); } while (num11 < 512); } else { int num12 = tree[num11 & 0x1FF]; int num13 = 1 << (num12 & 0xF); num12 = -(num12 >> 4); do { tree[num12 | (num11 >> 9)] = (short)((l << 4) | num10); num11 += 1 << (num10 & 0x1F); } while (num11 < num13); } array2[num10] = num2 + (1 << 16 - num10); } } public int GetSymbol(StreamManipulator input) { int num; int num2; if ((num = input.PeekBits(9)) >= 0) { if ((num2 = tree[num]) >= 0) { input.DropBits(num2 & 0xF); return num2 >> 4; } int num3 = -(num2 >> 4); int n = num2 & 0xF; if ((num = input.PeekBits(n)) >= 0) { num2 = tree[num3 | (num >> 9)]; input.DropBits(num2 & 0xF); return num2 >> 4; } int availableBits = input.AvailableBits; num = input.PeekBits(availableBits); num2 = tree[num3 | (num >> 9)]; if ((num2 & 0xF) <= availableBits) { input.DropBits(num2 & 0xF); return num2 >> 4; } return -1; } int availableBits2 = input.AvailableBits; num = input.PeekBits(availableBits2); num2 = tree[num]; if (num2 >= 0 && (num2 & 0xF) <= availableBits2) { input.DropBits(num2 & 0xF); return num2 >> 4; } return -1; } } internal class DeflaterHuffman { public class Tree { public short[] freqs; public byte[] length; public int minNumCodes; public int numCodes; private short[] codes; private int[] bl_counts; private int maxLength; private DeflaterHuffman dh; public Tree(DeflaterHuffman dh, int elems, int minCodes, int maxLength) { this.dh = dh; minNumCodes = minCodes; this.maxLength = maxLength; freqs = new short[elems]; bl_counts = new int[maxLength]; } public void Reset() { for (int i = 0; i < freqs.Length; i++) { freqs[i] = 0; } codes = null; length = null; } public void WriteSymbol(int code) { dh.pending.WriteBits(codes[code] & 0xFFFF, length[code]); } public void CheckEmpty() { bool flag = true; for (int i = 0; i < freqs.Length; i++) { if (freqs[i] != 0) { flag = false; } } if (!flag) { throw new SharpZipBaseException("!Empty"); } } public void SetStaticCodes(short[] stCodes, byte[] stLength) { codes = stCodes; length = stLength; } public void BuildCodes() { int num = freqs.Length; int[] array = new int[maxLength]; int num2 = 0; codes = new short[freqs.Length]; for (int i = 0; i < maxLength; i++) { array[i] = num2; num2 += bl_counts[i] << 15 - i; } for (int j = 0; j < numCodes; j++) { int num3 = length[j]; if (num3 > 0) { codes[j] = BitReverse(array[num3 - 1]); array[num3 - 1] += 1 << 16 - num3; } } } private void BuildLength(int[] childs) { length = new byte[freqs.Length]; int num = childs.Length / 2; int num2 = (num + 1) / 2; int num3 = 0; for (int i = 0; i < maxLength; i++) { bl_counts[i] = 0; } int[] array = new int[num]; array[num - 1] = 0; for (int num4 = num - 1; num4 >= 0; num4--) { if (childs[2 * num4 + 1] != -1) { int num5 = array[num4] + 1; if (num5 > maxLength) { num5 = maxLength; num3++; } int num6 = num5; array[childs[2 * num4 + 1]] = num6; array[childs[2 * num4]] = num6; } else { int num7 = array[num4]; bl_counts[num7 - 1]++; length[childs[2 * num4]] = (byte)array[num4]; } } if (num3 == 0) { return; } int num8 = maxLength - 1; while (true) { if (bl_counts[--num8] != 0) { do { bl_counts[num8]--; bl_counts[++num8]++; num3 -= 1 << ((maxLength - 1 - num8) & 0x1F); } while (num3 > 0 && num8 < maxLength - 1); if (num3 <= 0) { break; } } } bl_counts[maxLength - 1] += num3; bl_counts[maxLength - 2] -= num3; int num9 = 2 * num2; for (int num10 = maxLength; num10 != 0; num10--) { int num11 = bl_counts[num10 - 1]; while (num11 > 0) { int num12 = 2 * childs[num9++]; if (childs[num12 + 1] == -1) { length[childs[num12]] = (byte)num10; num11--; } } } } public void BuildTree() { int num = freqs.Length; int[] array = new int[num]; int num2 = 0; int num3 = 0; for (int i = 0; i < num; i++) { int num4 = freqs[i]; if (num4 != 0) { int num5 = num2++; int num6; while (num5 > 0 && freqs[array[num6 = (num5 - 1) / 2]] > num4) { array[num5] = array[num6]; num5 = num6; } array[num5] = i; num3 = i; } } while (num2 < 2) { int num7 = ((num3 < 2) ? (++num3) : 0); array[num2++] = num7; } numCodes = Math.Max(num3 + 1, minNumCodes); int num8 = num2; int[] array2 = new int[4 * num2 - 2]; int[] array3 = new int[2 * num2 - 1]; int num9 = num8; for (int j = 0; j < num2; j++) { int num10 = (array2[2 * j] = array[j]); array2[2 * j + 1] = -1; array3[j] = freqs[num10] << 8; array[j] = j; } do { int num11 = array[0]; int num12 = array[--num2]; int num13 = 0; int num14; for (num14 = 1; num14 < num2; num14 = num14 * 2 + 1) { if (num14 + 1 < num2 && array3[array[num14]] > array3[array[num14 + 1]]) { num14++; } array[num13] = array[num14]; num13 = num14; } int num15 = array3[num12]; while ((num14 = num13) > 0 && array3[array[num13 = (num14 - 1) / 2]] > num15) { array[num14] = array[num13]; } array[num14] = num12; int num16 = array[0]; num12 = num9++; array2[2 * num12] = num11; array2[2 * num12 + 1] = num16; int num17 = Math.Min(array3[num11] & 0xFF, array3[num16] & 0xFF); num15 = (array3[num12] = array3[num11] + array3[num16] - num17 + 1); num13 = 0; for (num14 = 1; num14 < num2; num14 = num13 * 2 + 1) { if (num14 + 1 < num2 && array3[array[num14]] > array3[array[num14 + 1]]) { num14++; } array[num13] = array[num14]; num13 = num14; } while ((num14 = num13) > 0 && array3[array[num13 = (num14 - 1) / 2]] > num15) { array[num14] = array[num13]; } array[num14] = num12; } while (num2 > 1); if (array[0] != array2.Length / 2 - 1) { throw new SharpZipBaseException("Heap invariant violated"); } BuildLength(array2); } public int GetEncodedLength() { int num = 0; for (int i = 0; i < freqs.Length; i++) { num += freqs[i] * length[i]; } return num; } public void CalcBLFreq(Tree blTree) { int num = -1; int num2 = 0; while (num2 < numCodes) { int num3 = 1; int num4 = length[num2]; int num5; int num6; if (num4 == 0) { num5 = 138; num6 = 3; } else { num5 = 6; num6 = 3; if (num != num4) { blTree.freqs[num4]++; num3 = 0; } } num = num4; num2++; while (num2 < numCodes && num == length[num2]) { num2++; if (++num3 >= num5) { break; } } if (num3 < num6) { blTree.freqs[num] += (short)num3; } else if (num != 0) { blTree.freqs[REP_3_6]++; } else if (num3 <= 10) { blTree.freqs[REP_3_10]++; } else { blTree.freqs[REP_11_138]++; } } } public void WriteTree(Tree blTree) { int num = -1; int num2 = 0; while (num2 < numCodes) { int num3 = 1; int num4 = length[num2]; int num5; int num6; if (num4 == 0) { num5 = 138; num6 = 3; } else { num5 = 6; num6 = 3; if (num != num4) { blTree.WriteSymbol(num4); num3 = 0; } } num = num4; num2++; while (num2 < numCodes && num == length[num2]) { num2++; if (++num3 >= num5) { break; } } if (num3 < num6) { while (num3-- > 0) { blTree.WriteSymbol(num); } } else if (num != 0) { blTree.WriteSymbol(REP_3_6); dh.pending.WriteBits(num3 - 3, 2); } else if (num3 <= 10) { blTree.WriteSymbol(REP_3_10); dh.pending.WriteBits(num3 - 3, 3); } else { blTree.WriteSymbol(REP_11_138); dh.pending.WriteBits(num3 - 11, 7); } } } } private static int BUFSIZE; private static int LITERAL_NUM; private static int DIST_NUM; private static int BITLEN_NUM; private static int REP_3_6; private static int REP_3_10; private static int REP_11_138; private static int EOF_SYMBOL; private static int[] BL_ORDER; private static byte[] bit4Reverse; public DeflaterPending pending; private Tree literalTree; private Tree distTree; private Tree blTree; private short[] d_buf; private byte[] l_buf; private int last_lit; private int extra_bits; private static short[] staticLCodes; private static byte[] staticLLength; private static short[] staticDCodes; private static byte[] staticDLength; public DeflaterHuffman(DeflaterPending pending) { this.pending = pending; literalTree = new Tree(this, LITERAL_NUM, 257, 15); distTree = new Tree(this, DIST_NUM, 1, 15); blTree = new Tree(this, BITLEN_NUM, 4, 7); d_buf = new short[BUFSIZE]; l_buf = new byte[BUFSIZE]; } static DeflaterHuffman() { BUFSIZE = 16384; LITERAL_NUM = 286; DIST_NUM = 30; BITLEN_NUM = 19; REP_3_6 = 16; REP_3_10 = 17; REP_11_138 = 18; EOF_SYMBOL = 256; BL_ORDER = new int[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; bit4Reverse = new byte[16] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 }; staticLCodes = new short[LITERAL_NUM]; staticLLength = new byte[LITERAL_NUM]; int num = 0; while (num < 144) { staticLCodes[num] = BitReverse(48 + num << 8); staticLLength[num++] = 8; } while (num < 256) { staticLCodes[num] = BitReverse(256 + num << 7); staticLLength[num++] = 9; } while (num < 280) { staticLCodes[num] = BitReverse(-256 + num << 9); staticLLength[num++] = 7; } while (num < LITERAL_NUM) { staticLCodes[num] = BitReverse(-88 + num << 8); staticLLength[num++] = 8; } staticDCodes = new short[DIST_NUM]; staticDLength = new byte[DIST_NUM]; for (num = 0; num < DIST_NUM; num++) { staticDCodes[num] = BitReverse(num << 11); staticDLength[num] = 5; } } public static short BitReverse(int toReverse) { return (short)((bit4Reverse[toReverse & 0xF] << 12) | (bit4Reverse[(toReverse >> 4) & 0xF] << 8) | (bit4Reverse[(toReverse >> 8) & 0xF] << 4) | bit4Reverse[toReverse >> 12]); } public void Reset() { last_lit = 0; extra_bits = 0; literalTree.Reset(); distTree.Reset(); blTree.Reset(); } private int Lcode(int len) { if (len == 255) { return 285; } int num = 257; while (len >= 8) { num += 4; len >>= 1; } return num + len; } private int Dcode(int distance) { int num = 0; while (distance >= 4) { num += 2; distance >>= 1; } return num + distance; } public void SendAllTrees(int blTreeCodes) { blTree.BuildCodes(); literalTree.BuildCodes(); distTree.BuildCodes(); pending.WriteBits(literalTree.numCodes - 257, 5); pending.WriteBits(distTree.numCodes - 1, 5); pending.WriteBits(blTreeCodes - 4, 4); for (int i = 0; i < blTreeCodes; i++) { pending.WriteBits(blTree.length[BL_ORDER[i]], 3); } literalTree.WriteTree(blTree); distTree.WriteTree(blTree); } public void CompressBlock() { for (int i = 0; i < last_lit; i++) { int num = l_buf[i] & 0xFF; int num2 = d_buf[i]; if (num2-- != 0) { int num3 = Lcode(num); literalTree.WriteSymbol(num3); int num4 = (num3 - 261) / 4; if (num4 > 0 && num4 <= 5) { pending.WriteBits(num & ((1 << num4) - 1), num4); } int num5 = Dcode(num2); distTree.WriteSymbol(num5); num4 = num5 / 2 - 1; if (num4 > 0) { pending.WriteBits(num2 & ((1 << num4) - 1), num4); } } else { literalTree.WriteSymbol(num); } } literalTree.WriteSymbol(EOF_SYMBOL); } public void FlushStoredBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) { pending.WriteBits(0 + (lastBlock ? 1 : 0), 3); pending.AlignToByte(); pending.WriteShort(storedLength); pending.WriteShort(~storedLength); pending.WriteBlock(stored, storedOffset, storedLength); Reset(); } public void FlushBlock(byte[] stored, int storedOffset, int storedLength, bool lastBlock) { literalTree.freqs[EOF_SYMBOL]++; literalTree.BuildTree(); distTree.BuildTree(); literalTree.CalcBLFreq(blTree); distTree.CalcBLFreq(blTree); blTree.BuildTree(); int num = 4; for (int num2 = 18; num2 > num; num2--) { if (blTree.length[BL_ORDER[num2]] > 0) { num = num2 + 1; } } int num3 = 14 + num * 3 + blTree.GetEncodedLength() + literalTree.GetEncodedLength() + distTree.GetEncodedLength() + extra_bits; int num4 = extra_bits; for (int i = 0; i < LITERAL_NUM; i++) { num4 += literalTree.freqs[i] * staticLLength[i]; } for (int j = 0; j < DIST_NUM; j++) { num4 += distTree.freqs[j] * staticDLength[j]; } if (num3 >= num4) { num3 = num4; } if (storedOffset >= 0 && storedLength + 4 < num3 >> 3) { FlushStoredBlock(stored, storedOffset, storedLength, lastBlock); } else if (num3 == num4) { pending.WriteBits(2 + (lastBlock ? 1 : 0), 3); literalTree.SetStaticCodes(staticLCodes, staticLLength); distTree.SetStaticCodes(staticDCodes, staticDLength); CompressBlock(); Reset(); } else { pending.WriteBits(4 + (lastBlock ? 1 : 0), 3); SendAllTrees(num); CompressBlock(); Reset(); } } public bool IsFull() { return last_lit >= BUFSIZE; } public bool TallyLit(int lit) { d_buf[last_lit] = 0; l_buf[last_lit++] = (byte)lit; literalTree.freqs[lit]++; return IsFull(); } public bool TallyDist(int dist, int len) { d_buf[last_lit] = (short)dist; l_buf[last_lit++] = (byte)(len - 3); int num = Lcode(len - 3); literalTree.freqs[num]++; if (num >= 265 && num < 285) { extra_bits += (num - 261) / 4; } int num2 = Dcode(dist - 1); distTree.freqs[num2]++; if (num2 >= 4) { extra_bits += num2 / 2 - 1; } return IsFull(); } } internal class DeflaterPending : PendingBuffer { public DeflaterPending() : base(65536) { } } internal enum DeflateStrategy { Default, Filtered, HuffmanOnly } internal class DeflaterEngine : DeflaterConstants { private static int TOO_FAR = 4096; private int ins_h; private short[] head; private short[] prev; private int matchStart; private int matchLen; private bool prevAvailable; private int blockStart; private int strstart; private int lookahead; private byte[] window; private DeflateStrategy strategy; private int max_chain; private int max_lazy; private int niceLength; private int goodLength; private int comprFunc; private byte[] inputBuf; private int totalIn; private int inputOff; private int inputEnd; private DeflaterPending pending; private DeflaterHuffman huffman; private Adler32 adler; public int Adler => (int)adler.Value; public int TotalIn => totalIn; public DeflateStrategy Strategy { get { return strategy; } set { strategy = value; } } public DeflaterEngine(DeflaterPending pending) { this.pending = pending; huffman = new DeflaterHuffman(pending); adler = new Adler32(); window = new byte[65536]; head = new short[32768]; prev = new short[32768]; strstart = 1; blockStart = 1; } public void Reset() { huffman.Reset(); adler.Reset(); strstart = 1; blockStart = 1; lookahead = 0; totalIn = 0; prevAvailable = false; matchLen = 2; for (int i = 0; i < 32768; i++) { head[i] = 0; } for (int j = 0; j < 32768; j++) { prev[j] = 0; } } public void ResetAdler() { adler.Reset(); } public void SetLevel(int lvl) { goodLength = DeflaterConstants.GOOD_LENGTH[lvl]; max_lazy = DeflaterConstants.MAX_LAZY[lvl]; niceLength = DeflaterConstants.NICE_LENGTH[lvl]; max_chain = DeflaterConstants.MAX_CHAIN[lvl]; if (DeflaterConstants.COMPR_FUNC[lvl] == comprFunc) { return; } switch (comprFunc) { case 0: if (strstart > blockStart) { huffman.FlushStoredBlock(window, blockStart, strstart - blockStart, lastBlock: false); blockStart = strstart; } UpdateHash(); break; case 1: if (strstart > blockStart) { huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock: false); blockStart = strstart; } break; case 2: if (prevAvailable) { huffman.TallyLit(window[strstart - 1] & 0xFF); } if (strstart > blockStart) { huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock: false); blockStart = strstart; } prevAvailable = false; matchLen = 2; break; } comprFunc = DeflaterConstants.COMPR_FUNC[lvl]; } private void UpdateHash() { ins_h = (window[strstart] << 5) ^ window[strstart + 1]; } private int InsertString() { int num = ((ins_h << 5) ^ window[strstart + 2]) & 0x7FFF; short num2 = head[num]; short num3 = num2; prev[strstart & 0x7FFF] = num2; head[num] = (short)strstart; ins_h = num; return num3 & 0xFFFF; } private void SlideWindow() { Array.Copy(window, 32768, window, 0, 32768); matchStart -= 32768; strstart -= 32768; blockStart -= 32768; for (int i = 0; i < 32768; i++) { int num = head[i] & 0xFFFF; head[i] = (short)((num >= 32768) ? (num - 32768) : 0); } for (int j = 0; j < 32768; j++) { int num2 = prev[j] & 0xFFFF; prev[j] = (short)((num2 >= 32768) ? (num2 - 32768) : 0); } } public void FillWindow() { if (strstart >= 65274) { SlideWindow(); } while (lookahead < 262 && inputOff < inputEnd) { int num = 65536 - lookahead - strstart; if (num > inputEnd - inputOff) { num = inputEnd - inputOff; } Array.Copy(inputBuf, inputOff, window, strstart + lookahead, num); adler.Update(inputBuf, inputOff, num); inputOff += num; totalIn += num; lookahead += num; } if (lookahead >= 3) { UpdateHash(); } } private bool FindLongestMatch(int curMatch) { int num = max_chain; int num2 = niceLength; short[] array = prev; int num3 = strstart; int num4 = strstart + matchLen; int num5 = Math.Max(matchLen, 2); int num6 = Math.Max(strstart - 32506, 0); int num7 = strstart + 258 - 1; byte b = window[num4 - 1]; byte b2 = window[num4]; if (num5 >= goodLength) { num >>= 2; } if (num2 > lookahead) { num2 = lookahead; } do { if (window[curMatch + num5] != b2 || window[curMatch + num5 - 1] != b || window[curMatch] != window[num3] || window[curMatch + 1] != window[num3 + 1]) { continue; } int num8 = curMatch + 2; num3 += 2; while (window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && window[++num3] == window[++num8] && num3 < num7) { } if (num3 > num4) { matchStart = curMatch; num4 = num3; num5 = num3 - strstart; if (num5 >= num2) { break; } b = window[num4 - 1]; b2 = window[num4]; } num3 = strstart; } while ((curMatch = array[curMatch & 0x7FFF] & 0xFFFF) > num6 && --num != 0); matchLen = Math.Min(num5, lookahead); return matchLen >= 3; } public void SetDictionary(byte[] buffer, int offset, int length) { adler.Update(buffer, offset, length); if (length >= 3) { if (length > 32506) { offset += length - 32506; length = 32506; } Array.Copy(buffer, offset, window, strstart, length); UpdateHash(); length--; while (--length > 0) { InsertString(); strstart++; } strstart += 2; blockStart = strstart; } } private bool DeflateStored(bool flush, bool finish) { if (!flush && lookahead == 0) { return false; } strstart += lookahead; lookahead = 0; int num = strstart - blockStart; if (num >= DeflaterConstants.MAX_BLOCK_SIZE || (blockStart < 32768 && num >= 32506) || flush) { bool flag = finish; if (num > DeflaterConstants.MAX_BLOCK_SIZE) { num = DeflaterConstants.MAX_BLOCK_SIZE; flag = false; } huffman.FlushStoredBlock(window, blockStart, num, flag); blockStart += num; return !flag; } return true; } private bool DeflateFast(bool flush, bool finish) { if (lookahead < 262 && !flush) { return false; } while (lookahead >= 262 || flush) { if (lookahead == 0) { huffman.FlushBlock(window, blockStart, strstart - blockStart, finish); blockStart = strstart; return false; } if (strstart > 65274) { SlideWindow(); } int num; if (lookahead >= 3 && (num = InsertString()) != 0 && strategy != DeflateStrategy.HuffmanOnly && strstart - num <= 32506 && FindLongestMatch(num)) { if (huffman.TallyDist(strstart - matchStart, matchLen)) { bool lastBlock = finish && lookahead == 0; huffman.FlushBlock(window, blockStart, strstart - blockStart, lastBlock); blockStart = strstart; } lookahead -= matchLen; if (matchLen <= max_lazy && lookahead >= 3) { while (--matchLen > 0) { strstart++; InsertString(); } strstart++; } else { strstart += matchLen; if (lookahead >= 2) { UpdateHash(); } } matchLen = 2; } else { huffman.TallyLit(window[strstart] & 0xFF); strstart++; lookahead--; if (huffman.IsFull()) { bool flag = finish && lookahead == 0; huffman.FlushBlock(window, blockStart, strstart - blockStart, flag); blockStart = strstart; return !flag; } } } return true; } private bool DeflateSlow(bool flush, bool finish) { if (lookahead < 262 && !flush) { return false; } while (lookahead >= 262 || flush) { if (lookahead == 0) { if (prevAvailable) { huffman.TallyLit(window[strstart - 1] & 0xFF); } prevAvailable = false; huffman.FlushBlock(window, blockStart, strstart - blockStart, finish); blockStart = strstart; return false; } if (strstart >= 65274) { SlideWindow(); } int num = matchStart; int num2 = matchLen; if (lookahead >= 3) { int num3 = InsertString(); if (strategy != DeflateStrategy.HuffmanOnly && num3 != 0 && strstart - num3 <= 32506 && FindLongestMatch(num3) && matchLen <= 5 && (strategy == DeflateStrategy.Filtered || (matchLen == 3 && strstart - matchStart > TOO_FAR))) { matchLen = 2; } } if (num2 >= 3 && matchLen <= num2) { huffman.TallyDist(strstart - 1 - num, num2); num2 -= 2; do { strstart++; lookahead--; if (lookahead >= 3) { InsertString(); } } while (--num2 > 0); strstart++; lookahead--; prevAvailable = false; matchLen = 2; } else { if (prevAvailable) { huffman.TallyLit(window[strstart - 1] & 0xFF); } prevAvailable = true; strstart++; lookahead--; } if (huffman.IsFull()) { int num4 = strstart - blockStart; if (prevAvailable) { num4--; } bool flag = finish && lookahead == 0 && !prevAvailable; huffman.FlushBlock(window, blockStart, num4, flag); blockStart += num4; return !flag; } } return true; } public bool Deflate(bool flush, bool finish) { bool flag; do { FillWindow(); bool flush2 = flush && inputOff == inputEnd; flag = comprFunc switch { 0 => DeflateStored(flush2, finish), 1 => DeflateFast(flush2, finish), 2 => DeflateSlow(flush2, finish), _ => throw new InvalidOperationException("unknown comprFunc"), }; } while (pending.IsFlushed && flag); return flag; } public void SetInput(byte[] buf, int off, int len) { if (inputOff < inputEnd) { throw new InvalidOperationException("Old input was not completely processed"); } int num = off + len; if (0 > off || off > num || num > buf.Length) { throw new ArgumentOutOfRangeException(); } inputBuf = buf; inputOff = off; inputEnd = num; } public bool NeedsInput() { return inputEnd == inputOff; } } internal class PendingBuffer { protected byte[] buf; private int start; private int end; private uint bits; private int bitCount; public int BitCount => bitCount; public bool IsFlushed => end == 0; public PendingBuffer() : this(4096) { } public PendingBuffer(int bufsize) { buf = new byte[bufsize]; } public void Reset() { bitCount = 0; end = 0; start = 0; } public void WriteByte(int b) { buf[end++] = (byte)b; } public void WriteShort(int s) { buf[end++] = (byte)s; buf[end++] = (byte)(s >> 8); } public void WriteInt(int s) { buf[end++] = (byte)s; buf[end++] = (byte)(s >> 8); buf[end++] = (byte)(s >> 16); buf[end++] = (byte)(s >> 24); } public void WriteBlock(byte[] block, int offset, int len) { Array.Copy(block, offset, buf, end, len); end += len; } public void AlignToByte() { if (bitCount > 0) { buf[end++] = (byte)bits; if (bitCount > 8) { buf[end++] = (byte)(bits >> 8); } } bits = 0u; bitCount = 0; } public void WriteBits(int b, int count) { bits |= (uint)(b << bitCount); bitCount += count; if (bitCount >= 16) { buf[end++] = (byte)bits; buf[end++] = (byte)(bits >> 8); bits >>= 16; bitCount -= 16; } } public void WriteShortMSB(int s) { buf[end++] = (byte)(s >> 8); buf[end++] = (byte)s; } public int Flush(byte[] output, int offset, int length) { if (bitCount >= 8) { buf[end++] = (byte)bits; bits >>= 8; bitCount -= 8; } if (length > end - start) { length = end - start; Array.Copy(buf, start, output, offset, length); start = 0; end = 0; } else { Array.Copy(buf, start, output, offset, length); start += length; } return length; } public byte[] ToByteArray() { byte[] array = new byte[end - start]; Array.Copy(buf, start, array, 0, array.Length); start = 0; end = 0; return array; } } internal class DeflaterConstants { public const bool DEBUGGING = false; public const int STORED_BLOCK = 0; public const int STATIC_TREES = 1; public const int DYN_TREES = 2; public const int PRESET_DICT = 32; public const int DEFAULT_MEM_LEVEL = 8; public const int MAX_MATCH = 258; public const int MIN_MATCH = 3; public const int MAX_WBITS = 15; public const int WSIZE = 32768; public const int WMASK = 32767; public const int HASH_BITS = 15; public const int HASH_SIZE = 32768; public const int HASH_MASK = 32767; public const int HASH_SHIFT = 5; public const int MIN_LOOKAHEAD = 262; public const int MAX_DIST = 32506; public const int PENDING_BUF_SIZE = 65536; public const int DEFLATE_STORED = 0; public const int DEFLATE_FAST = 1; public const int DEFLATE_SLOW = 2; public static int MAX_BLOCK_SIZE = Math.Min(65535, 65531); public static int[] GOOD_LENGTH = new int[10] { 0, 4, 4, 4, 4, 8, 8, 8, 32, 32 }; public static int[] MAX_LAZY = new int[10] { 0, 4, 5, 6, 4, 16, 16, 32, 128, 258 }; public static int[] NICE_LENGTH = new int[10] { 0, 8, 16, 32, 16, 32, 128, 128, 258, 258 }; public static int[] MAX_CHAIN = new int[10] { 0, 4, 8, 32, 16, 32, 128, 256, 1024, 4096 }; public static int[] COMPR_FUNC = new int[10] { 0, 1, 1, 1, 1, 2, 2, 2, 2, 2 }; } internal class Inflater { private const int DECODE_HEADER = 0; private const int DECODE_DICT = 1; private const int DECODE_BLOCKS = 2; private const int DECODE_STORED_LEN1 = 3; private const int DECODE_STORED_LEN2 = 4; private const int DECODE_STORED = 5; private const int DECODE_DYN_HEADER = 6; private const int DECODE_HUFFMAN = 7; private const int DECODE_HUFFMAN_LENBITS = 8; private const int DECODE_HUFFMAN_DIST = 9; private const int DECODE_HUFFMAN_DISTBITS = 10; private const int DECODE_CHKSUM = 11; private const int FINISHED = 12; private static int[] CPLENS = new int[29] { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 }; private static int[] CPLEXT = new int[29] { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0 }; private static int[] CPDIST = new int[30] { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 }; private static int[] CPDEXT = new int[30] { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 }; private int mode; private int readAdler; private int neededBits; private int repLength; private int repDist; private int uncomprLen; private bool isLastBlock; private int totalOut; private int totalIn; private bool noHeader; private StreamManipulator input; private OutputWindow outputWindow; private InflaterDynHeader dynHeader; private InflaterHuffmanTree litlenTree; private InflaterHuffmanTree distTree; private Adler32 adler; public bool IsNeedingInput => input.IsNeedingInput; public bool IsNeedingDictionary => mode == 1 && neededBits == 0; public bool IsFinished => mode == 12 && outputWindow.GetAvailable() == 0; public int Adler => (int)((!IsNeedingDictionary) ? adler.Value : readAdler); public int TotalOut => totalOut; public int TotalIn => totalIn - RemainingInput; public int RemainingInput => input.AvailableBytes; public Inflater() : this(noHeader: false) { } public Inflater(bool noHeader) { this.noHeader = noHeader; adler = new Adler32(); input = new StreamManipulator(); outputWindow = new OutputWindow(); mode = (noHeader ? 2 : 0); } public void Reset() { mode = (noHeader ? 2 : 0); totalOut = 0; totalIn = 0; input.Reset(); outputWindow.Reset(); dynHeader = null; litlenTree = null; distTree = null; isLastBlock = false; adler.Reset(); } private bool DecodeHeader() { int num = input.PeekBits(16); if (num < 0) { return false; } input.DropBits(16); num = ((num << 8) | (num >> 8)) & 0xFFFF; if (num % 31 != 0) { throw new SharpZipBaseException("Header checksum illegal"); } if ((num & 0xF00) != Deflater.DEFLATED << 8) { throw new SharpZipBaseException("Compression Method unknown"); } if ((num & 0x20) == 0) { mode = 2; } else { mode = 1; neededBits = 32; } return true; } private bool DecodeDict() { while (neededBits > 0) { int num = input.PeekBits(8); if (num < 0) { return false; } input.DropBits(8); readAdler = (readAdler << 8) | num; neededBits -= 8; } return false; } private bool DecodeHuffman() { int num = outputWindow.GetFreeSpace(); while (num >= 258) { switch (mode) { case 7: { int symbol; while (((symbol = litlenTree.GetSymbol(input)) & -256) == 0) { outputWindow.Write(symbol); if (--num < 258) { return true; } } if (symbol < 257) { if (symbol < 0) { return false; } distTree = null; litlenTree = null; mode = 2; return true; } try { repLength = CPLENS[symbol - 257]; neededBits = CPLEXT[symbol - 257]; } catch (Exception) { throw new SharpZipBaseException("Illegal rep length code"); } goto case 8; } case 8: if (neededBits > 0) { mode = 8; int num2 = input.PeekBits(neededBits); if (num2 < 0) { return false; } input.DropBits(neededBits); repLength += num2; } mode = 9; goto case 9; case 9: { int symbol = distTree.GetSymbol(input); if (symbol < 0) { return false; } try { repDist = CPDIST[symbol]; neededBits = CPDEXT[symbol]; } catch (Exception) { throw new SharpZipBaseException("Illegal rep dist code"); } goto case 10; } case 10: if (neededBits > 0) { mode = 10; int num3 = input.PeekBits(neededBits); if (num3 < 0) { return false; } input.DropBits(neededBits); repDist += num3; } break; default: throw new SharpZipBaseException("Inflater unknown mode"); } outputWindow.Repeat(repLength, repDist); num -= repLength; mode = 7; } return true; } private bool DecodeChksum() { while (neededBits > 0) { int num = input.PeekBits(8); if (num < 0) { return false; } input.DropBits(8); readAdler = (readAdler << 8) | num; neededBits -= 8; } if ((int)adler.Value != readAdler) { throw new SharpZipBaseException("Adler chksum doesn't match: " + (int)adler.Value + " vs. " + readAdler); } mode = 12; return false; } private bool Decode() { switch (mode) { case 0: return DecodeHeader(); case 1: return DecodeDict(); case 11: return DecodeChksum(); case 2: { if (isLastBlock) { if (noHeader) { mode = 12; return false; } input.SkipToByteBoundary(); neededBits = 32; mode = 11; return true; } int num = input.PeekBits(3); if (num < 0) { return false; } input.DropBits(3); if (((uint)num & (true ? 1u : 0u)) != 0) { isLastBlock = true; } switch (num >> 1) { case 0: input.SkipToByteBoundary(); mode = 3; break; case 1: litlenTree = InflaterHuffmanTree.defLitLenTree; distTree = InflaterHuffmanTree.defDistTree; mode = 7; break; case 2: dynHeader = new InflaterDynHeader(); mode = 6; break; default: throw new SharpZipBaseException("Unknown block type " + num); } return true; } case 3: if ((uncomprLen = input.PeekBits(16)) < 0) { return false; } input.DropBits(16); mode = 4; goto case 4; case 4: { int num3 = input.PeekBits(16); if (num3 < 0) { return false; } input.DropBits(16); if (num3 != (uncomprLen ^ 0xFFFF)) { throw new SharpZipBaseException("broken uncompressed block"); } mode = 5; goto case 5; } case 5: { int num2 = outputWindow.CopyStored(input, uncomprLen); uncomprLen -= num2; if (uncomprLen == 0) { mode = 2; return true; } return !input.IsNeedingInput; } case 6: if (!dynHeader.Decode(input)) { return false; } litlenTree = dynHeader.BuildLitLenTree(); distTree = dynHeader.BuildDistTree(); mode = 7; goto case 7; case 7: case 8: case 9: case 10: return DecodeHuffman(); case 12: return false; default: throw new SharpZipBaseException("Inflater.Decode unknown mode"); } } public void SetDictionary(byte[] buffer) { SetDictionary(buffer, 0, buffer.Length); } public void SetDictionary(byte[] buffer, int offset, int len) { if (!IsNeedingDictionary) { throw new InvalidOperationException(); } adler.Update(buffer, offset, len); if ((int)adler.Value != readAdler) { throw new SharpZipBaseException("Wrong adler checksum"); } adler.Reset(); outputWindow.CopyDict(buffer, offset, len); mode = 2; } public void SetInput(byte[] buf) { SetInput(buf, 0, buf.Length); } public void SetInput(byte[] buffer, int offset, int length) { input.SetInput(buffer, offset, length); totalIn += length; } public int Inflate(byte[] buf) { return Inflate(buf, 0, buf.Length); } public int Inflate(byte[] buf, int offset, int len) { if (len < 0) { throw new ArgumentOutOfRangeException("len < 0"); } if (len == 0) { if (!IsFinished) { Decode(); } return 0; } int num = 0; do { if (mode != 11) { int num2 = outputWindow.CopyOutput(buf, offset, len); adler.Update(buf, offset, num2); offset += num2; num += num2; totalOut += num2; len -= num2; if (len == 0) { return num; } } } while (Decode() || (outputWindow.GetAvailable() > 0 && mode != 11)); return num; } } internal class Deflater { public static int BEST_COMPRESSION = 9; public static int BEST_SPEED = 1; public static int DEFAULT_COMPRESSION = -1; public static int NO_COMPRESSION; public static int DEFLATED = 8; private static int IS_SETDICT = 1; private static int IS_FLUSHING = 4; private static int IS_FINISHING = 8; private static int INIT_STATE; private static int SETDICT_STATE = 1; private static int BUSY_STATE = 16; private static int FLUSHING_STATE = 20; private static int FINISHING_STATE = 28; private static int FINISHED_STATE = 30; private static int CLOSED_STATE = 127; private int level; private bool noZlibHeaderOrFooter; private int state; private long totalOut; private DeflaterPending pending; private DeflaterEngine engine; public int Adler => engine.Adler; public int TotalIn => engine.TotalIn; public long TotalOut => totalOut; public bool IsFinished => state == FINISHED_STATE && pending.IsFlushed; public bool IsNeedingInput => engine.NeedsInput(); public Deflater() : this(DEFAULT_COMPRESSION, noZlibHeaderOrFooter: false) { } public Deflater(int lvl) : this(lvl, noZlibHeaderOrFooter: false) { } public Deflater(int level, bool noZlibHeaderOrFooter) { if (level == DEFAULT_COMPRESSION) { level = 6; } else if (level < NO_COMPRESSION || level > BEST_COMPRESSION) { throw new ArgumentOutOfRangeException("level"); } pending = new DeflaterPending(); engine = new DeflaterEngine(pending); this.noZlibHeaderOrFooter = noZlibHeaderOrFooter; SetStrategy(DeflateStrategy.Default); SetLevel(level); Reset(); } public void Reset() { state = ((!noZlibHeaderOrFooter) ? INIT_STATE : BUSY_STATE); totalOut = 0L; pending.Reset(); engine.Reset(); } public void Flush() { state |= IS_FLUSHING; } public void Finish() { state |= IS_FLUSHING | IS_FINISHING; } public void SetInput(byte[] input) { SetInput(input, 0, input.Length); } public void SetInput(byte[] input, int off, int len) { if ((state & IS_FINISHING) != 0) { throw new InvalidOperationException("finish()/end() already called"); } engine.SetInput(input, off, len); } public void SetLevel(int lvl) { if (lvl == DEFAULT_COMPRESSION) { lvl = 6; } else if (lvl < NO_COMPRESSION || lvl > BEST_COMPRESSION) { throw new ArgumentOutOfRangeException("lvl"); } if (level != lvl) { level = lvl; engine.SetLevel(lvl); } } public int GetLevel() { return level; } public void SetStrategy(DeflateStrategy strategy) { engine.Strategy = strategy; } public int Deflate(byte[] output) { return Deflate(output, 0, output.Length); } public int Deflate(byte[] output, int offset, int length) { int num = length; if (state == CLOSED_STATE) { throw new InvalidOperationException("Deflater closed"); } if (state < BUSY_STATE) { int num2 = DEFLATED + 112 << 8; int num3 = level - 1 >> 1; if (num3 < 0 || num3 > 3) { num3 = 3; } num2 |= num3 << 6; if ((state & IS_SETDICT) != 0) { num2 |= 0x20; } num2 += 31 - num2 % 31; pending.WriteShortMSB(num2); if ((state & IS_SETDICT) != 0) { int adler = engine.Adler; engine.ResetAdler(); pending.WriteShortMSB(adler >> 16); pending.WriteShortMSB(adler & 0xFFFF); } state = BUSY_STATE | (state & (IS_FLUSHING | IS_FINISHING)); } while (true) { int num4 = pending.Flush(output, offset, length); offset += num4; totalOut += num4; length -= num4; if (length == 0 || state == FINISHED_STATE) { break; } if (engine.Deflate((state & IS_FLUSHING) != 0, (state & IS_FINISHING) != 0)) { continue; } if (state == BUSY_STATE) { return num - length; } if (state == FLUSHING_STATE) { if (level != NO_COMPRESSION) { for (int num5 = 8 + (-pending.BitCount & 7); num5 > 0; num5 -= 10) { pending.WriteBits(2, 10); } } state = BUSY_STATE; } else if (state == FINISHING_STATE) { pending.AlignToByte(); if (!noZlibHeaderOrFooter) { int adler2 = engine.Adler; pending.WriteShortMSB(adler2 >> 16); pending.WriteShortMSB(adler2 & 0xFFFF); } state = FINISHED_STATE; } } return num - length; } public void SetDictionary(byte[] dict) { SetDictionary(dict, 0, dict.Length); } public void SetDictionary(byte[] dict, int offset, int length) { if (state != INIT_STATE) { throw new InvalidOperationException(); } state = SETDICT_STATE; engine.SetDictionary(dict, offset, length); } } internal class InflaterDynHeader { private const int LNUM = 0; private const int DNUM = 1; private const int BLNUM = 2; private const int BLLENS = 3; private const int LENS = 4; private const int REPS = 5; private static readonly int[] repMin = new int[3] { 3, 3, 11 }; private static readonly int[] repBits = new int[3] { 2, 3, 7 }; private byte[] blLens; private byte[] litdistLens; private InflaterHuffmanTree blTree; private int mode; private int lnum; private int dnum; private int blnum; private int num; private int repSymbol; private byte lastLen; private int ptr; private static readonly int[] BL_ORDER = new int[19] { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; public bool Decode(StreamManipulator input) { while (true) { switch (mode) { default: continue; case 0: lnum = input.PeekBits(5); if (lnum < 0) { return false; } lnum += 257; input.DropBits(5); mode = 1; goto case 1; case 1: dnum = input.PeekBits(5); if (dnum < 0) { return false; } dnum++; input.DropBits(5); this.num = lnum + dnum; litdistLens = new byte[this.num]; mode = 2; goto case 2; case 2: blnum = input.PeekBits(4); if (blnum < 0) { return false; } blnum += 4; input.DropBits(4); blLens = new byte[19]; ptr = 0; mode = 3; goto case 3; case 3: while (ptr < blnum) { int num = input.PeekBits(3); if (num < 0) { return false; } input.DropBits(3); blLens[BL_ORDER[ptr]] = (byte)num; ptr++; } blTree = new InflaterHuffmanTree(blLens); blLens = null; ptr = 0; mode = 4; goto case 4; case 4: { int symbol; while (((symbol = blTree.GetSymbol(input)) & -16) == 0) { byte b = (lastLen = (byte)symbol); litdistLens[ptr++] = b; if (ptr == this.num) { return true; } } if (symbol < 0) { return false; } if (symbol >= 17) { lastLen = 0; } else if (ptr == 0) { throw new SharpZipBaseException(); } repSymbol = symbol - 16; mode = 5; break; } case 5: break; } int n = repBits[repSymbol]; int num2 = input.PeekBits(n); if (num2 < 0) { return false; } input.DropBits(n); num2 += repMin[repSymbol]; if (ptr + num2 > this.num) { throw new SharpZipBaseException(); } while (num2-- > 0) { litdistLens[ptr++] = lastLen; } if (ptr == this.num) { break; } mode = 4; } return true; } public InflaterHuffmanTree BuildLitLenTree() { byte[] array = new byte[lnum]; Array.Copy(litdistLens, 0, array, 0, lnum); return new InflaterHuffmanTree(array); } public InflaterHuffmanTree BuildDistTree() { byte[] array = new byte[dnum]; Array.Copy(litdistLens, lnum, array, 0, dnum); return new InflaterHuffmanTree(array); } } } namespace ICSharpCode.SharpZipLib.Zip { internal class ZipInputStream : InflaterInputStream { private delegate int ReaderDelegate(byte[] b, int offset, int length); private ReaderDelegate internalReader; private Crc32 crc = new Crc32(); private ZipEntry entry; private long size; private int method; private int flags; private string password; public string Password { get { return password; } set { password = value; } } public bool CanDecompressEntry => entry != null && entry.Version <= 20; public override int Available => (entry != null) ? 1 : 0; public ZipInputStream(Stream baseInputStream) : base(baseInputStream, new Inflater(noHeader: true)) { internalReader = InitialRead; } public ZipEntry GetNextEntry() { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry != null) { CloseEntry(); } int num = inputBuffer.ReadLeInt(); switch (num) { case 33639248: case 84233040: case 101010256: case 101075792: Close(); return null; case 134695760: case 808471376: num = inputBuffer.ReadLeInt(); break; } if (num != 67324752) { throw new ZipException("Wrong Local header signature: 0x" + $"{num:X}"); } short versionRequiredToExtract = (short)inputBuffer.ReadLeShort(); flags = inputBuffer.ReadLeShort(); method = inputBuffer.ReadLeShort(); uint num2 = (uint)inputBuffer.ReadLeInt(); int num3 = inputBuffer.ReadLeInt(); csize = inputBuffer.ReadLeInt(); size = inputBuffer.ReadLeInt(); int num4 = inputBuffer.ReadLeShort(); int num5 = inputBuffer.ReadLeShort(); bool flag = (flags & 1) == 1; byte[] array = new byte[num4]; inputBuffer.ReadRawBuffer(array); string name = ZipConstants.ConvertToString(array); entry = new ZipEntry(name, versionRequiredToExtract); entry.Flags = flags; if (method == 0 && ((!flag && csize != size) || (flag && csize - 12 != size))) { throw new ZipException("Stored, but compressed != uncompressed"); } if (method != 0 && method != 8) { throw new ZipException("Unknown compression method " + method); } entry.CompressionMethod = (CompressionMethod)method; if ((flags & 8) == 0) { entry.Crc = num3 & 0xFFFFFFFFL; entry.Size = size & 0xFFFFFFFFL; entry.CompressedSize = csize & 0xFFFFFFFFL; } else { if (num3 != 0) { entry.Crc = num3 & 0xFFFFFFFFL; } if (size != 0L) { entry.Size = size & 0xFFFFFFFFL; } if (csize != 0L) { entry.CompressedSize = csize & 0xFFFFFFFFL; } } entry.DosTime = num2; if (num5 > 0) { byte[] array2 = new byte[num5]; inputBuffer.ReadRawBuffer(array2); entry.ExtraData = array2; } internalReader = InitialRead; return entry; } private void ReadDataDescriptor() { if (inputBuffer.ReadLeInt() != 134695760) { throw new ZipException("Data descriptor signature not found"); } entry.Crc = inputBuffer.ReadLeInt() & 0xFFFFFFFFL; csize = inputBuffer.ReadLeInt(); size = inputBuffer.ReadLeInt(); entry.Size = size & 0xFFFFFFFFL; entry.CompressedSize = csize & 0xFFFFFFFFL; } public void CloseEntry() { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry == null) { return; } if (method == 8) { if (((uint)flags & 8u) != 0) { byte[] array = new byte[2048]; while (Read(array, 0, array.Length) > 0) { } return; } csize -= inf.TotalIn; inputBuffer.Available -= inf.RemainingInput; } if (inputBuffer.Available > csize && csize >= 0) { inputBuffer.Available = (int)(inputBuffer.Available - csize); } else { csize -= inputBuffer.Available; inputBuffer.Available = 0; while (csize != 0L) { int num = (int)Skip(csize & 0xFFFFFFFFL); if (num <= 0) { throw new ZipException("Zip archive ends early."); } csize -= num; } } size = 0L; crc.Reset(); if (method == 8) { inf.Reset(); } entry = null; } public override int ReadByte() { byte[] array = new byte[1]; if (Read(array, 0, 1) <= 0) { return -1; } return array[0] & 0xFF; } private int InitialRead(byte[] destination, int offset, int count) { if (entry.Version > 20) { throw new ZipException("Libray cannot extract this entry version required (" + entry.Version + ")"); } if (entry.IsCrypted) { if (password == null) { throw new ZipException("No password set."); } PkzipClassicManaged pkzipClassicManaged = new PkzipClassicManaged(); byte[] rgbKey = PkzipClassic.GenerateKeys(Encoding.ASCII.GetBytes(password)); inputBuffer.CryptoTransform = pkzipClassicManaged.CreateDecryptor(rgbKey, null); byte[] array = new byte[12]; inputBuffer.ReadClearTextBuffer(array, 0, 12); if ((flags & 8) == 0) { if (array[11] != (byte)(entry.Crc >> 24)) { throw new ZipException("Invalid password"); } } else if (array[11] != (byte)((entry.DosTime >> 8) & 0xFF)) { throw new ZipException("Invalid password"); } if (csize >= 12) { csize -= 12L; } } else { inputBuffer.CryptoTransform = null; } if (method == 8 && inputBuffer.Available > 0) { inputBuffer.SetInflaterInput(inf); } internalReader = BodyRead; return BodyRead(destination, offset, count); } public override int Read(byte[] destination, int index, int count) { return internalReader(destination, index, count); } public int BodyRead(byte[] b, int off, int len) { if (crc == null) { throw new InvalidOperationException("Closed."); } if (entry == null || len <= 0) { return 0; } bool flag = false; switch (method) { case 8: len = base.Read(b, off, len); if (len <= 0) { if (!inf.IsFinished) { throw new ZipException("Inflater not finished!?"); } inputBuffer.Available = inf.RemainingInput; if ((flags & 8) == 0 && (inf.TotalIn != csize || inf.TotalOut != size)) { throw new ZipException("size mismatch: " + csize + ";" + size + " <-> " + inf.TotalIn + ";" + inf.TotalOut); } inf.Reset(); flag = true; } break; case 0: if (len > csize && csize >= 0) { len = (int)csize; } len = inputBuffer.ReadClearTextBuffer(b, off, len); if (len > 0) { csize -= len; size -= len; } if (csize == 0L) { flag = true; } else if (len < 0) { throw new ZipException("EOF in stored block"); } break; } if (len > 0) { crc.Update(b, off, len); } if (flag) { StopDecrypting(); if (((uint)flags & 8u) != 0) { ReadDataDescriptor(); } if ((crc.Value & 0xFFFFFFFFL) != entry.Crc && entry.Crc != -1) { throw new ZipException("CRC mismatch"); } crc.Reset(); entry = null; } return len; } public override void Close() { base.Close(); crc = null; entry = null; } } internal enum CompressionMethod { Stored = 0, Deflated = 8, Deflate64 = 9, BZip2 = 11, WinZipAES = 99 } [Flags] internal enum GeneralBitFlags { Encrypted = 1, Method = 6, Descriptor = 8, Reserved = 0x10, Patched = 0x20, StrongEncryption = 0x40, EnhancedCompress = 0x1000, HeaderMasked = 0x2000 } internal sealed class ZipConstants { public const int VERSION_MADE_BY = 20; public const int VERSION_STRONG_ENCRYPTION = 50; public const int LOCHDR = 30; public const int LOCSIG = 67324752; public const int LOCVER = 4; public const int LOCFLG = 6; public const int LOCHOW = 8; public const int LOCTIM = 10; public const int LOCCRC = 14; public const int LOCSIZ = 18; public const int LOCLEN = 22; public const int LOCNAM = 26; public const int LOCEXT = 28; public const int SPANNINGSIG = 134695760; public const int SPANTEMPSIG = 808471376; public const int EXTSIG = 134695760; public const int EXTHDR = 16; public const int EXTCRC = 4; public const int EXTSIZ = 8; public const int EXTLEN = 12; public const int CENSIG = 33639248; public const int CENHDR = 46; public const int CENVEM = 4; public const int CENVER = 6; public const int CENFLG = 8; public const int CENHOW = 10; public const int CENTIM = 12; public const int CENCRC = 16; public const int CENSIZ = 20; public const int CENLEN = 24; public const int CENNAM = 28; public const int CENEXT = 30; public const int CENCOM = 32; public const int CENDSK = 34; public const int CENATT = 36; public const int CENATX = 38; public const int CENOFF = 42; public const int CENSIG64 = 101075792; public const int CENDIGITALSIG = 84233040; public const int ENDSIG = 101010256; public const int ENDHDR = 22; public const int ENDNRD = 4; public const int ENDDCD = 6; public const int ENDSUB = 8; public const int ENDTOT = 10; public const int ENDSIZ = 12; public const int ENDOFF = 16; public const int ENDCOM = 20; public const int CRYPTO_HEADER_SIZE = 12; private static int defaultCodePage; public static int DefaultCodePage { get { return defaultCodePage; } set { defaultCodePage = value; } } public static string ConvertToString(byte[] data, int length) { return Encoding.GetEncoding(DefaultCodePage).GetString(data, 0, length); } public static string ConvertToString(byte[] data) { return ConvertToString(data, data.Length); } public static byte[] ConvertToArray(string str) { return Encoding.GetEncoding(DefaultCodePage).GetBytes(str); } } internal class ZipNameTransform : INameTransform { private string trimPrefix; private bool relativePath; public string TrimPrefix { get { return trimPrefix; } set { trimPrefix = value; } } public ZipNameTransform() { relativePath = true; } public ZipNameTransform(bool useRelativePaths) { relativePath = useRelativePaths; } public ZipNameTransform(bool useRelativePaths, string trimPrefix) { this.trimPrefix = trimPrefix; relativePath = useRelativePaths; } public string TransformDirectory(string name) { name = TransformFile(name); if (name.Length > 0) { if (!name.EndsWith("/")) { name += "/"; } } else { name = "/"; } return name; } public string TransformFile(string name) { if (name != null) { if (trimPrefix != null && name.IndexOf(trimPrefix) == 0) { name = name.Substring(trimPrefix.Length); } if (Path.IsPathRooted(name)) { name = name.Substring(Path.GetPathRoot(name).Length); } if (relativePath) { if (name.Length > 0 && (name[0] == Path.AltDirectorySeparatorChar || name[0] == Path.DirectorySeparatorChar)) { name = name.Remove(0, 1); } } else if (name.Length > 0 && name[0] != Path.AltDirectorySeparatorChar && name[0] != Path.DirectorySeparatorChar) { name = name.Insert(0, "/"); } name = name.Replace("\\", "/"); } else { name = ""; } return name; } } internal class ZipOutputStream : DeflaterOutputStream { private ArrayList entries = new ArrayList(); private Crc32 crc = new Crc32(); private ZipEntry curEntry; private int defaultCompressionLevel = Deflater.DEFAULT_COMPRESSION; private CompressionMethod curMethod = CompressionMethod.Deflated; private long size; private long offset; private byte[] zipComment = new byte[0]; private bool patchEntryHeader; private long headerPatchPos = -1L; public bool IsFinished => entries == null; public ZipOutputStream(Stream baseOutputStream) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, noZlibHeaderOrFooter: true)) { } public void SetComment(string comment) { byte[] array = ZipConstants.ConvertToArray(comment); if (array.Length > 65535) { throw new ArgumentOutOfRangeException("comment"); } zipComment = array; } public void SetLevel(int level) { defaultCompressionLevel = level; def.SetLevel(level); } public int GetLevel() { return def.GetLevel(); } private void WriteLeShort(int value) { baseOutputStream.WriteByte((byte)((uint)value & 0xFFu)); baseOutputStream.WriteByte((byte)((uint)(value >> 8) & 0xFFu)); } private void WriteLeInt(int value) { WriteLeShort(value); WriteLeShort(value >> 16); } private void WriteLeLong(long value) { WriteLeInt((int)value); WriteLeInt((int)(value >> 32)); } public void PutNextEntry(ZipEntry entry) { if (entries == null) { throw new InvalidOperationException("ZipOutputStream was finished"); } if (curEntry != null) { CloseEntry(); } if (entries.Count >= 65535) { throw new ZipException("Too many entries for Zip file"); } CompressionMethod compressionMethod = entry.CompressionMethod; int level = defaultCompressionLevel; entry.Flags = 0; patchEntryHeader = false; bool flag = true; if (compressionMethod == CompressionMethod.Stored) { if (entry.CompressedSize >= 0) { if (entry.Size < 0) { entry.Size = entry.CompressedSize; } else if (entry.Size != entry.CompressedSize) { throw new ZipException("Method STORED, but compressed size != size"); } } else if (entry.Size >= 0) { entry.CompressedSize = entry.Size; } if (entry.Size < 0 || entry.Crc < 0) { if (base.CanPatchEntries) { flag = false; } else { compressionMethod = CompressionMethod.Deflated; level = 0; } } } if (compressionMethod == CompressionMethod.Deflated) { if (entry.Size == 0L) { entry.CompressedSize = entry.Size; entry.Crc = 0L; compressionMethod = CompressionMethod.Stored; } else if (entry.CompressedSize < 0 || entry.Size < 0 || entry.Crc < 0) { flag = false; } } if (!flag) { if (!base.CanPatchEntries) { entry.Flags |= 8; } else { patchEntryHeader = true; } } if (base.Password != null) { entry.IsCrypted = true; if (entry.Crc < 0) { entry.Flags |= 8; } } entry.Offset = (int)offset; entry.CompressionMethod = compressionMethod; curMethod = compressionMethod; WriteLeInt(67324752); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((byte)compressionMethod); WriteLeInt((int)entry.DosTime); if (flag) { WriteLeInt((int)entry.Crc); WriteLeInt((int)((!entry.IsCrypted) ? entry.CompressedSize : ((int)entry.CompressedSize + 12))); WriteLeInt((int)entry.Size); } else { if (patchEntryHeader) { headerPatchPos = baseOutputStream.Position; } WriteLeInt(0); WriteLeInt(0); WriteLeInt(0); } byte[] array = ZipConstants.ConvertToArray(entry.Name); if (array.Length > 65535) { throw new ZipException("Entry name too long."); } byte[] array2 = entry.ExtraData; if (array2 == null) { array2 = new byte[0]; } if (array2.Length > 65535) { throw new ZipException("Extra data too long."); } WriteLeShort(array.Length); WriteLeShort(array2.Length); baseOutputStream.Write(array, 0, array.Length); baseOutputStream.Write(array2, 0, array2.Length); offset += 30 + array.Length + array2.Length; curEntry = entry; crc.Reset(); if (compressionMethod == CompressionMethod.Deflated) { def.Reset(); def.SetLevel(level); } size = 0L; if (entry.IsCrypted) { if (entry.Crc < 0) { WriteEncryptionHeader(entry.DosTime << 16); } else { WriteEncryptionHeader(entry.Crc); } } } public void CloseEntry() { if (curEntry == null) { throw new InvalidOperationException("No open entry"); } if (curMethod == CompressionMethod.Deflated) { base.Finish(); } long num = ((curMethod != CompressionMethod.Deflated) ? size : def.TotalOut); if (curEntry.Size < 0) { curEntry.Size = size; } else if (curEntry.Size != size) { throw new ZipException("size was " + size + ", but I expected " + curEntry.Size); } if (curEntry.CompressedSize < 0) { curEntry.CompressedSize = num; } else if (curEntry.CompressedSize != num) { throw new ZipException("compressed size was " + num + ", but I expected " + curEntry.CompressedSize); } if (curEntry.Crc < 0) { curEntry.Crc = crc.Value; } else if (curEntry.Crc != crc.Value) { throw new ZipException("crc was " + crc.Value + ", but I expected " + curEntry.Crc); } offset += num; if (offset > 4294967295L) { throw new ZipException("Maximum Zip file size exceeded"); } if (curEntry.IsCrypted) { curEntry.CompressedSize += 12L; } if (patchEntryHeader) { long position = baseOutputStream.Position; baseOutputStream.Seek(headerPatchPos, SeekOrigin.Begin); WriteLeInt((int)curEntry.Crc); WriteLeInt((int)curEntry.CompressedSize); WriteLeInt((int)curEntry.Size); baseOutputStream.Seek(position, SeekOrigin.Begin); patchEntryHeader = false; } if (((uint)curEntry.Flags & 8u) != 0) { WriteLeInt(134695760); WriteLeInt((int)curEntry.Crc); WriteLeInt((int)curEntry.CompressedSize); WriteLeInt((int)curEntry.Size); offset += 16L; } entries.Add(curEntry); curEntry = null; } private void WriteEncryptionHeader(long crcValue) { offset += 12L; InitializePassword(base.Password); byte[] array = new byte[12]; Random random = new Random(); random.NextBytes(array); array[11] = (byte)(crcValue >> 24); EncryptBlock(array, 0, array.Length); baseOutputStream.Write(array, 0, array.Length); } public override void Write(byte[] b, int off, int len) { if (curEntry == null) { throw new InvalidOperationException("No open entry."); } if (len <= 0) { return; } crc.Update(b, off, len); size += len; if (size > 4294967295L || size < 0) { throw new ZipException("Maximum entry size exceeded"); } switch (curMethod) { case CompressionMethod.Deflated: base.Write(b, off, len); break; case CompressionMethod.Stored: if (base.Password != null) { byte[] array = new byte[len]; Array.Copy(b, off, array, 0, len); EncryptBlock(array, 0, len); baseOutputStream.Write(array, off, len); } else { baseOutputStream.Write(b, off, len); } break; } } public override void Finish() { if (entries == null) { return; } if (curEntry != null) { CloseEntry(); } int num = 0; int num2 = 0; foreach (ZipEntry entry in entries) { CompressionMethod compressionMethod = entry.CompressionMethod; WriteLeInt(33639248); WriteLeShort(20); WriteLeShort(entry.Version); WriteLeShort(entry.Flags); WriteLeShort((short)compressionMethod); WriteLeInt((int)entry.DosTime); WriteLeInt((int)entry.Crc); WriteLeInt((int)entry.CompressedSize); WriteLeInt((int)entry.Size); byte[] array = ZipConstants.ConvertToArray(entry.Name); if (array.Length > 65535) { throw new ZipException("Name too long."); } byte[] array2 = entry.ExtraData; if (array2 == null) { array2 = new byte[0]; } byte[] array3 = ((entry.Comment == null) ? new byte[0] : ZipConstants.ConvertToArray(entry.Comment)); if (array3.Length > 65535) { throw new ZipException("Comment too long."); } WriteLeShort(array.Length); WriteLeShort(array2.Length); WriteLeShort(array3.Length); WriteLeShort(0); WriteLeShort(0); if (entry.ExternalFileAttributes != -1) { WriteLeInt(entry.ExternalFileAttributes); } else if (entry.IsDirectory) { WriteLeInt(16); } else { WriteLeInt(0); } WriteLeInt(entry.Offset); baseOutputStream.Write(array, 0, array.Length); baseOutputStream.Write(array2, 0, array2.Length); baseOutputStream.Write(array3, 0, array3.Length); num++; num2 += 46 + array.Length + array2.Length + array3.Length; } WriteLeInt(101010256); WriteLeShort(0); WriteLeShort(0); WriteLeShort(num); WriteLeShort(num); WriteLeInt(num2); WriteLeInt((int)offset); WriteLeShort(zipComment.Length); baseOutputStream.Write(zipComment, 0, zipComment.Length); baseOutputStream.Flush(); entries = null; } } internal class FastZipEvents { public ProcessDirectoryDelegate ProcessDirectory; public ProcessFileDelegate ProcessFile; public DirectoryFailureDelegate DirectoryFailure; public FileFailureDelegate FileFailure; public void OnDirectoryFailure(string directory, Exception e) { if (DirectoryFailure != null) { ScanFailureEventArgs e2 = new ScanFailureEventArgs(directory, e); DirectoryFailure(this, e2); } } public void OnFileFailure(string file, Exception e) { if (FileFailure != null) { ScanFailureEventArgs e2 = new ScanFailureEventArgs(file, e); FileFailure(this, e2); } } public void OnProcessFile(string file) { if (ProcessFile != null) { ScanEventArgs e = new ScanEventArgs(file); ProcessFile(this, e); } } public void OnProcessDirectory(string directory, bool hasMatchingFiles) { if (ProcessDirectory != null) { DirectoryEventArgs e = new DirectoryEventArgs(directory, hasMatchingFiles); ProcessDirectory(this, e); } } } internal class FastZip { public enum Overwrite { Prompt, Never, Always } public delegate bool ConfirmOverwriteDelegate(string fileName); private byte[] buffer; private ZipOutputStream outputStream; private ZipInputStream inputStream; private string password; private string targetDirectory; private string sourceDirectory; private NameFilter fileFilter; private NameFilter directoryFilter; private Overwrite overwrite; private ConfirmOverwriteDelegate confirmDelegate; private bool restoreDateTime; private bool createEmptyDirectories; private FastZipEvents events; private ZipNameTransform nameTransform; public bool CreateEmptyDirectories { get { return createEmptyDirectories; } set { createEmptyDirectories = value; } } public ZipNameTransform NameTransform { get { return nameTransform; } set { if (value == null) { nameTransform = new ZipNameTransform(); } else { nameTransform = value; } } } public FastZip() { events = null; } public FastZip(FastZipEvents events) { this.events = events; } public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter, string directoryFilter) { NameTransform = new ZipNameTransform(useRelativePaths: true, sourceDirectory); this.sourceDirectory = sourceDirectory; outputStream = new ZipOutputStream(File.Create(zipFileName)); try { FileSystemScanner fileSystemScanner = new FileSystemScanner(fileFilter, directoryFilter); fileSystemScanner.ProcessFile = (ProcessFileDelegate)Delegate.Combine(fileSystemScanner.ProcessFile, new ProcessFileDelegate(ProcessFile)); if (CreateEmptyDirectories) { fileSystemScanner.ProcessDirectory = (ProcessDirectoryDelegate)Delegate.Combine(fileSystemScanner.ProcessDirectory, new ProcessDirectoryDelegate(ProcessDirectory)); } fileSystemScanner.Scan(sourceDirectory, recurse); } finally { outputStream.Close(); } } public void CreateZip(string zipFileName, string sourceDirectory, bool recurse, string fileFilter) { CreateZip(zipFileName, sourceDirectory, recurse, fileFilter, null); } public void ExtractZip(string zipFileName, string targetDirectory, string fileFilter) { ExtractZip(zipFileName, targetDirectory, Overwrite.Always, null, fileFilter, null); } public void ExtractZip(string zipFileName, string targetDirectory, Overwrite overwrite, ConfirmOverwriteDelegate confirmDelegate, string fileFilter, string directoryFilter) { if (overwrite == Overwrite.Prompt && confirmDelegate == null) { throw new ArgumentNullException("confirmDelegate"); } this.overwrite = overwrite; this.confirmDelegate = confirmDelegate; this.targetDirectory = targetDirectory; this.fileFilter = new NameFilter(fileFilter); this.directoryFilter = new NameFilter(directoryFilter); inputStream = new ZipInputStream(File.OpenRead(zipFileName)); try { if (password != null) { inputStream.Password = password; } ZipEntry nextEntry; while ((nextEntry = inputStream.GetNextEntry()) != null) { if (this.directoryFilter.IsMatch(Path.GetDirectoryName(nextEntry.Name)) && this.fileFilter.IsMatch(nextEntry.Name)) { ExtractEntry(nextEntry); } } } finally { inputStream.Close(); } } private void ProcessDirectory(object sender, DirectoryEventArgs e) { if (!e.HasMatchingFiles && createEmptyDirectories) { if (events != null) { events.OnProcessDirectory(e.Name, e.HasMatchingFiles); } if (e.Name != sourceDirectory) { string name = nameTransform.TransformDirectory(e.Name); ZipEntry entry = new ZipEntry(name); outputStream.PutNextEntry(entry); } } } private void ProcessFile(object sender, ScanEventArgs e) { if (events != null) { events.OnProcessFile(e.Name); } string name = nameTransform.TransformFile(e.Name); ZipEntry entry = new ZipEntry(name); outputStream.PutNextEntry(entry); AddFileContents(e.Name); } private void AddFileContents(string name) { if (buffer == null) { buffer = new byte[4096]; } FileStream fileStream = File.OpenRead(name); try { int num; do { num = fileStream.Read(buffer, 0, buffer.Length); outputStream.Write(buffer, 0, num); } while (num > 0); } finally { fileStream.Close(); } } private void ExtractFileEntry(ZipEntry entry, string targetName) { bool flag = true; if (overwrite == Overwrite.Prompt && confirmDelegate != null && File.Exists(targetName)) { flag = confirmDelegate(targetName); } if (!flag) { return; } if (events != null) { events.OnProcessFile(entry.Name); } FileStream fileStream = File.Create(targetName); try { if (buffer == null) { buffer = new byte[4096]; } int num; do { num = inputStream.Read(buffer, 0, buffer.Length); fileStream.Write(buffer, 0, num); } while (num > 0); } finally { fileStream.Close(); } if (restoreDateTime) { File.SetLastWriteTime(targetName, entry.DateTime); } } private bool NameIsValid(string name) { return name != null && name.Length > 0 && name.IndexOfAny(Path.InvalidPathChars) < 0; } private void ExtractEntry(ZipEntry entry) { bool flag = NameIsValid(entry.Name); string path = null; string text = null; if (flag) { string text2; if (Path.IsPathRooted(entry.Name)) { string pathRoot = Path.GetPathRoot(entry.Name); pathRoot = entry.Name.Substring(pathRoot.Length); text2 = Path.Combine(Path.GetDirectoryName(pathRoot), Path.GetFileName(entry.Name)); } else { text2 = entry.Name; } text = Path.Combine(targetDirectory, text2); path = Path.GetDirectoryName(Path.GetFullPath(text)); flag = flag && text2.Length > 0; } if (flag && !Directory.Exists(path) && (!entry.IsDirectory || CreateEmptyDirectories)) { try { Directory.CreateDirectory(path); } catch { flag = false; } } if (flag && entry.IsFile) { ExtractFileEntry(entry, text); } } } internal class ZipException : SharpZipBaseException { public ZipException() { } public ZipException(string msg) : base(msg) { } } internal class KeysRequiredEventArgs : EventArgs { private string fileName; private byte[] key; public string FileName => fileName; public byte[] Key { get { return key; } set { key = value; } } public KeysRequiredEventArgs(string name) { fileName = name; } public KeysRequiredEventArgs(string name, byte[] keyValue) { fileName = name; key = keyValue; } } internal class ZipFile : IEnumerable { private class ZipEntryEnumeration : IEnumerator { private ZipEntry[] array; private int ptr = -1; public object Current => array[ptr]; public ZipEntryEnumeration(ZipEntry[] arr) { array = arr; } public void Reset() { ptr = -1; } public bool MoveNext() { return ++ptr < array.Length; } } private class PartialInputStream : InflaterInputStream { private Stream baseStream; private long filepos; private long end; public override int Available { get { long num = end - filepos; if (num > int.MaxValue) { return int.MaxValue; } return (int)num; } } public PartialInputStream(Stream baseStream, long start, long len) : base(baseStream) { this.baseStream = baseStream; filepos = start; end = start + len; } public override int ReadByte() { if (filepos == end) { return -1; } lock (baseStream) { baseStream.Seek(filepos++, SeekOrigin.Begin); return baseStream.ReadByte(); } } public override void Close() { } public override int Read(byte[] b, int off, int len) { if (len > end - filepos) { len = (int)(end - filepos); if (len == 0) { return 0; } } lock (baseStream) { baseStream.Seek(filepos, SeekOrigin.Begin); int num = baseStream.Read(b, off, len); if (num > 0) { filepos += len; } return num; } } public long SkipBytes(long amount) { if (amount < 0) { throw new ArgumentOutOfRangeException(); } if (amount > end - filepos) { amount = end - filepos; } filepos += amount; return amount; } } public delegate void KeysRequiredEventHandler(object sender, KeysRequiredEventArgs e); private string name; private string comment; private Stream baseStream; private bool isStreamOwner = true; private long offsetOfFirstEntry; private ZipEntry[] entries; public KeysRequiredEventHandler KeysRequired; private byte[] key; private byte[] iv; private byte[] Key { get { return key; } set { key = value; } } public string Password { set { if (value == null || value.Length == 0) { key = null; } else { key = PkzipClassic.GenerateKeys(Encoding.ASCII.GetBytes(value)); } } } private bool HaveKeys => key != null; private bool IsStreamOwner { get { return isStreamOwner; } set { isStreamOwner = value; } } [IndexerName("EntryByIndex")] public ZipEntry this[int index] => (ZipEntry)entries[index].Clone(); public string ZipFileComment => comment; public string Name => name; public int Size { get { if (entries != null) { return entries.Length; } throw new InvalidOperationException("ZipFile is closed"); } } public ZipFile(string name) { this.name = name; baseStream = File.OpenRead(name); try { ReadEntries(); } catch { Close(); throw; } } public ZipFile(FileStream file) { baseStream = file; name = file.Name; try { ReadEntries(); } catch { Close(); throw; } } public ZipFile(Stream baseStream) { this.baseStream = baseStream; name = null; try { ReadEntries(); } catch { Close(); throw; } } private void OnKeysRequired(string fileName) { if (KeysRequired != null) { KeysRequiredEventArgs keysRequiredEventArgs = new KeysRequiredEventArgs(fileName, key); KeysRequired(this, keysRequiredEventArgs); key = keysRequiredEventArgs.Key; } } private int ReadLeShort() { return baseStream.ReadByte() | (baseStream.ReadByte() << 8); } private int ReadLeInt() { return ReadLeShort() | (ReadLeShort() << 16); } private long LocateBlockWithSignature(int signature, long endLocation, int minimumBlockSize, int maximumVariableData) { long num = endLocation - minimumBlockSize; if (num < 0) { return -1L; } long num2 = Math.Max(num - maximumVariableData, 0L); do { if (num < num2) { return -1L; } baseStream.Seek(num--, SeekOrigin.Begin); } while (ReadLeInt() != signature); return baseStream.Position; } private void ReadEntries() { if (!baseStream.CanSeek) { throw new ZipException("ZipFile stream must be seekable"); } long num = LocateBlockWithSignature(101010256, baseStream.Length, 22, 65535); if (num < 0) { throw new ZipException("Cannot find central directory"); } int num2 = ReadLeShort(); int num3 = ReadLeShort(); int num4 = ReadLeShort(); int num5 = ReadLeShort(); int num6 = ReadLeInt(); int num7 = ReadLeInt(); int num8 = ReadLeShort(); byte[] array = new byte[num8]; baseStream.Read(array, 0, array.Length); comment = ZipConstants.ConvertToString(array); entries = new ZipEntry[num5]; if (num7 < num - (4 + num6)) { offsetOfFirstEntry = num - (4 + num6 + num7); if (offsetOfFirstEntry <= 0) { throw new ZipException("Invalid SFX file"); } } baseStream.Seek(offsetOfFirstEntry + num7, SeekOrigin.Begin); for (int i = 0; i < num4; i++) { if (ReadLeInt() != 33639248) { throw new ZipException("Wrong Central Directory signature"); } int madeByInfo = ReadLeShort(); int versionRequiredToExtract = ReadLeShort(); int flags = ReadLeShort(); int compressionMethod = ReadLeShort(); int num9 = ReadLeInt(); int num10 = ReadLeInt(); int num11 = ReadLeInt(); int num12 = ReadLeInt(); int num13 = ReadLeShort(); int num14 = ReadLeShort(); int num15 = ReadLeShort(); int num16 = ReadLeShort(); int num17 = ReadLeShort(); int externalFileAttributes = ReadLeInt(); int offset = ReadLeInt(); byte[] array2 = new byte[Math.Max(num13, num15)]; baseStream.Read(array2, 0, num13); string text = ZipConstants.ConvertToString(array2, num13); ZipEntry zipEntry = new ZipEntry(text, versionRequiredToExtract, madeByInfo); zipEntry.CompressionMethod = (CompressionMethod)compressionMethod; zipEntry.Crc = num10 & 0xFFFFFFFFL; zipEntry.Size = num12 & 0xFFFFFFFFL; zipEntry.CompressedSize = num11 & 0xFFFFFFFFL; zipEntry.Flags = flags; zipEntry.DosTime = (uint)num9; if (num14 > 0) { byte[] array3 = new byte[num14]; baseStream.Read(array3, 0, num14); zipEntry.ExtraData = array3; } if (num15 > 0) { baseStream.Read(array2, 0, num15); zipEntry.Comment = ZipConstants.ConvertToString(array2, num15); } zipEntry.ZipFileIndex = i; zipEntry.Offset = offset; zipEntry.ExternalFileAttributes = externalFileAttributes; entries[i] = zipEntry; } } public void Close() { entries = null; if (isStreamOwner) { lock (baseStream) { baseStream.Close(); } } } public IEnumerator GetEnumerator() { if (entries == null) { throw new InvalidOperationException("ZipFile has closed"); } return new ZipEntryEnumeration(entries); } public int FindEntry(string name, bool ignoreCase) { if (entries == null) { throw new InvalidOperationException("ZipFile has been closed"); } for (int i = 0; i < entries.Length; i++) { if (string.Compare(name, entries[i].Name, ignoreCase) == 0) { return i; } } return -1; } public ZipEntry GetEntry(string name) { if (entries == null) { throw new InvalidOperationException("ZipFile has been closed"); } int num = FindEntry(name, ignoreCase: true); return (num < 0) ? null : ((ZipEntry)entries[num].Clone()); } public bool TestArchive(bool testData) { bool result = true; try { for (int i = 0; i < Size; i++) { long num = TestLocalHeader(this[i], fullTest: true, extractTest: true); if (testData) { Stream inputStream = GetInputStream(this[i]); Crc32 crc = new Crc32(); byte[] array = new byte[4096]; int len; while ((len = inputStream.Read(array, 0, array.Length)) > 0) { crc.Update(array, 0, len); } if (this[i].Crc != crc.Value) { result = false; break; } } } } catch { result = false; } return result; } private long TestLocalHeader(ZipEntry entry, bool fullTest, bool extractTest) { lock (baseStream) { baseStream.Seek(offsetOfFirstEntry + entry.Offset, SeekOrigin.Begin); if (ReadLeInt() != 67324752) { throw new ZipException("Wrong local header signature"); } short num = (short)ReadLeShort(); if (extractTest && num > 20) { throw new ZipException($"Version required to extract this entry not supported ({num})"); } short num2 = (short)ReadLeShort(); if (extractTest && ((uint)num2 & 0x3060u) != 0) { throw new ZipException("The library doesnt support the zip version required to extract this entry"); } if (num2 != entry.Flags) { throw new ZipException("Central header/local header flags mismatch"); } if (entry.CompressionMethod != (CompressionMethod)ReadLeShort()) { throw new ZipException("Central header/local header compression method mismatch"); } num = (short)ReadLeShort(); num = (short)ReadLeShort(); int num3 = ReadLeInt(); if (fullTest && (num2 & 8) == 0 && num3 != (int)entry.Crc) { throw new ZipException("Central header/local header crc mismatch"); } num3 = ReadLeInt(); num3 = ReadLeInt(); int num4 = ReadLeShort(); if (entry.Name.Length > num4) { throw new ZipException("file name length mismatch"); } int num5 = num4 + ReadLeShort(); return offsetOfFirstEntry + entry.Offset + 30 + num5; } } private long CheckLocalHeader(ZipEntry entry) { return TestLocalHeader(entry, fullTest: false, extractTest: true); } private void ReadFully(Stream s, byte[] outBuf) { int num = 0; int num2 = outBuf.Length; while (num2 > 0) { int num3 = s.Read(outBuf, num, num2); if (num3 <= 0) { throw new ZipException("Unexpected EOF"); } num += num3; num2 -= num3; } } private void CheckClassicPassword(CryptoStream classicCryptoStream, ZipEntry entry) { byte[] array = new byte[12]; ReadFully(classicCryptoStream, array); if ((entry.Flags & 8) == 0) { if (array[11] != (byte)(entry.Crc >> 24)) { throw new ZipException("Invalid password"); } } else if (array[11] != (byte)((entry.DosTime >> 8) & 0xFF)) { throw new ZipException("Invalid password"); } } private Stream CreateAndInitDecryptionStream(Stream baseStream, ZipEntry entry) { CryptoStream cryptoStream = null; if (entry.Version < 50 || (entry.Flags & 0x40) == 0) { PkzipClassicManaged pkzipClassicManaged = new PkzipClassicManaged(); OnKeysRequired(entry.Name); if (!HaveKeys) { throw new ZipException("No password available for encrypted stream"); } cryptoStream = new CryptoStream(baseStream, pkzipClassicManaged.CreateDecryptor(key, iv), CryptoStreamMode.Read); CheckClassicPassword(cryptoStream, entry); return cryptoStream; } throw new ZipException("Decryption method not supported"); } private void WriteEncryptionHeader(Stream stream, long crcValue) { byte[] array = new byte[12]; Random random = new Random(); random.NextBytes(array); array[11] = (byte)(crcValue >> 24); stream.Write(array, 0, array.Length); } private Stream CreateAndInitEncryptionStream(Stream baseStream, ZipEntry entry) { CryptoStream cryptoStream = null; if (entry.Version < 50 || (entry.Flags & 0x40) == 0) { PkzipClassicManaged pkzipClassicManaged = new PkzipClassicManaged(); OnKeysRequired(entry.Name); if (!HaveKeys) { throw new ZipException("No password available for encrypted stream"); } cryptoStream = new CryptoStream(baseStream, pkzipClassicManaged.CreateEncryptor(key, iv), CryptoStreamMode.Write); if (entry.Crc < 0 || ((uint)entry.Flags & 8u) != 0) { WriteEncryptionHeader(cryptoStream, entry.DosTime << 16); } else { WriteEncryptionHeader(cryptoStream, entry.Crc); } } return cryptoStream; } private Stream GetOutputStream(ZipEntry entry, string fileName) { baseStream.Seek(0L, SeekOrigin.End); Stream stream = File.OpenWrite(fileName); if (entry.IsCrypted) { stream = CreateAndInitEncryptionStream(stream, entry); } switch (entry.CompressionMethod) { case CompressionMethod.Deflated: stream = new DeflaterOutputStream(stream); break; default: throw new ZipException("Unknown compression method " + entry.CompressionMethod); case CompressionMethod.Stored: break; } return stream; } public Stream GetInputStream(ZipEntry entry) { if (entries == null) { throw new InvalidOperationException("ZipFile has closed"); } int num = entry.ZipFileIndex; if (num < 0 || num >= entries.Length || entries[num].Name != entry.Name) { num = FindEntry(entry.Name, ignoreCase: true); if (num < 0) { throw new IndexOutOfRangeException(); } } return GetInputStream(num); } public Stream GetInputStream(int entryIndex) { if (entries == null) { throw new InvalidOperationException("ZipFile has closed"); } long start = CheckLocalHeader(entries[entryIndex]); CompressionMethod compressionMethod = entries[entryIndex].CompressionMethod; Stream stream = new PartialInputStream(baseStream, start, entries[entryIndex].CompressedSize); if (entries[entryIndex].IsCrypted) { stream = CreateAndInitDecryptionStream(stream, entries[entryIndex]); if (stream == null) { throw new ZipException("Unable to decrypt this entry"); } } return compressionMethod switch { CompressionMethod.Stored => stream, CompressionMethod.Deflated => new InflaterInputStream(stream, new Inflater(noHeader: true)), _ => throw new ZipException("Unsupported compression method " + compressionMethod), }; } } internal class ZipEntry : ICloneable { private static int KNOWN_SIZE = 1; private static int KNOWN_CSIZE = 2; private static int KNOWN_CRC = 4; private static int KNOWN_TIME = 8; private static int KNOWN_EXTERN_ATTRIBUTES = 16; private ushort known; private int externalFileAttributes = -1; private ushort versionMadeBy; private string name; private ulong size; private ulong compressedSize; private ushort versionToExtract; private uint crc; private uint dosTime; private CompressionMethod method = CompressionMethod.Deflated; private byte[] extra; private string comment; private int flags; private int zipFileIndex = -1; private int offset; public bool IsCrypted { get { return (flags & 1) != 0; } set { if (value) { flags |= 1; } else { flags &= -2; } } } public int Flags { get { return flags; } set { flags = value; } } public int ZipFileIndex { get { return zipFileIndex; } set { zipFileIndex = value; } } public int Offset { get { return offset; } set { if ((value & -4294967296L) != 0L) { throw new ArgumentOutOfRangeException("Offset"); } offset = value; } } public int ExternalFileAttributes { get { if ((known & KNOWN_EXTERN_ATTRIBUTES) == 0) { return -1; } return externalFileAttributes; } set { externalFileAttributes = value; known |= (ushort)KNOWN_EXTERN_ATTRIBUTES; } } public int VersionMadeBy => versionMadeBy & 0xFF; public int HostSystem => (versionMadeBy >> 8) & 0xFF; public int Version { get { if (versionToExtract != 0) { return versionToExtract; } int result = 10; if (method == CompressionMethod.Deflated) { result = 20; } else if (IsDirectory) { result = 20; } else if (IsCrypted) { result = 20; } else if ((known & KNOWN_EXTERN_ATTRIBUTES) != 0 && ((uint)externalFileAttributes & 8u) != 0) { result = 11; } return result; } } public bool RequiresZip64 => size > 4294967295L || compressedSize > 4294967295L; public long DosTime { get { if ((known & KNOWN_TIME) == 0) { return 0L; } return dosTime; } set { dosTime = (uint)value; known |= (ushort)KNOWN_TIME; } } public DateTime DateTime { get { if (dosTime == 0) { return DateTime.Now; } uint second = 2 * (dosTime & 0x1F); uint minute = (dosTime >> 5) & 0x3Fu; uint hour = (dosTime >> 11) & 0x1Fu; uint day = (dosTime >> 16) & 0x1Fu; uint month = (dosTime >> 21) & 0xFu; uint year = ((dosTime >> 25) & 0x7F) + 1980; return new DateTime((int)year, (int)month, (int)day, (int)hour, (int)minute, (int)second); } set { DosTime = (uint)((((value.Year - 1980) & 0x7F) << 25) | (value.Month << 21) | (value.Day << 16) | (value.Hour << 11) | (value.Minute << 5) | (value.Second >>> 1)); } } public string Name => name; public long Size { get { return ((known & KNOWN_SIZE) == 0) ? (-1L) : ((long)size); } set { if ((value & -4294967296L) != 0L) { throw new ArgumentOutOfRangeException("size"); } size = (ulong)value; known |= (ushort)KNOWN_SIZE; } } public long CompressedSize { get { return ((known & KNOWN_CSIZE) == 0) ? (-1L) : ((long)compressedSize); } set { if ((value & -4294967296L) != 0L) { throw new ArgumentOutOfRangeException(); } compressedSize = (ulong)value; known |= (ushort)KNOWN_CSIZE; } } public long Crc { get { return ((known & KNOWN_CRC) == 0) ? (-1) : ((long)crc & 0xFFFFFFFFL); } set { if ((crc & -4294967296L) != 0L) { throw new ArgumentOutOfRangeException(); } crc = (uint)value; known |= (ushort)KNOWN_CRC; } } public CompressionMethod CompressionMethod { get { return method; } set { method = value; } } public byte[] ExtraData { get { return extra; } set { if (value == null) { extra = null; return; } if (value.Length > 65535) { throw new ArgumentOutOfRangeException(); } extra = new byte[value.Length]; Array.Copy(value, 0, extra, 0, value.Length); try { int num2; for (int i = 0; i < extra.Length; i += num2) { int num = (extra[i++] & 0xFF) | ((extra[i++] & 0xFF) << 8); num2 = (extra[i++] & 0xFF) | ((extra[i++] & 0xFF) << 8); if (num2 < 0 || i + num2 > extra.Length) { break; } switch (num) { case 21589: { int num3 = extra[i]; if (((uint)num3 & (true ? 1u : 0u)) != 0 && num2 >= 5) { int seconds = (extra[i + 1] & 0xFF) | ((extra[i + 2] & 0xFF) << 8) | ((extra[i + 3] & 0xFF) << 16) | ((extra[i + 4] & 0xFF) << 24); DateTime dateTime = new DateTime(1970, 1, 1, 0, 0, 0); TimeSpan timeSpan = new TimeSpan(0, 0, 0, seconds, 0); DateTime = (dateTime + timeSpan).ToLocalTime(); known |= (ushort)KNOWN_TIME; } break; } } } } catch (Exception) { } } } public string Comment { get { return comment; } set { if (value != null && value.Length > 65535) { throw new ArgumentOutOfRangeException(); } comment = value; } } public bool IsDirectory { get { int length = name.Length; bool flag = length > 0 && name[length - 1] == '/'; if (!flag && (known & KNOWN_EXTERN_ATTRIBUTES) != 0 && HostSystem == 0 && ((uint)ExternalFileAttributes & 0x10u) != 0) { flag = true; } return flag; } } public bool IsFile { get { bool flag = !IsDirectory; if (flag && (known & KNOWN_EXTERN_ATTRIBUTES) != 0 && HostSystem == 0 && ((uint)ExternalFileAttributes & 8u) != 0) { flag = false; } return flag; } } public ZipEntry(string name) : this(name, 0, 20) { } internal ZipEntry(string name, int versionRequiredToExtract) : this(name, versionRequiredToExtract, 20) { } internal ZipEntry(string name, int versionRequiredToExtract, int madeByInfo) { if (name == null) { throw new ArgumentNullException("ZipEntry name"); } if (name.Length == 0) { throw new ArgumentException("ZipEntry name is empty"); } if (versionRequiredToExtract != 0 && versionRequiredToExtract < 10) { throw new ArgumentOutOfRangeException("versionRequiredToExtract"); } DateTime = DateTime.Now; this.name = name; versionMadeBy = (ushort)madeByInfo; versionToExtract = (ushort)versionRequiredToExtract; } public ZipEntry(ZipEntry e) { known = e.known; name = e.name; size = e.size; compressedSize = e.compressedSize; crc = e.crc; dosTime = e.dosTime; method = e.method; ExtraData = e.ExtraData; comment = e.comment; versionToExtract = e.versionToExtract; versionMadeBy = e.versionMadeBy; externalFileAttributes = e.externalFileAttributes; flags = e.flags; zipFileIndex = -1; offset = 0; } public static string CleanName(string name, bool relativePath) { if (name == null) { return ""; } if (Path.IsPathRooted(name)) { name = name.Substring(Path.GetPathRoot(name).Length); } name = name.Replace("\\", "/"); if (relativePath) { if (name.Length > 0 && (name[0] == Path.AltDirectorySeparatorChar || name[0] == Path.DirectorySeparatorChar)) { name = name.Remove(0, 1); } } else if (name.Length > 0 && name[0] != Path.AltDirectorySeparatorChar && name[0] != Path.DirectorySeparatorChar) { name = name.Insert(0, "/"); } return name; } public static string CleanName(string name) { return CleanName(name, relativePath: true); } public object Clone() { return MemberwiseClone(); } public override string ToString() { return name; } } } namespace ICSharpCode.SharpZipLib.Checksums { internal class StrangeCRC : IChecksum { private static readonly uint[] crc32Table = new uint[256] { 0u, 79764919u, 159529838u, 222504665u, 319059676u, 398814059u, 445009330u, 507990021u, 638119352u, 583659535u, 797628118u, 726387553u, 890018660u, 835552979u, 1015980042u, 944750013u, 1276238704u, 1221641927u, 1167319070u, 1095957929u, 1595256236u, 1540665371u, 1452775106u, 1381403509u, 1780037320u, 1859660671u, 1671105958u, 1733955601u, 2031960084u, 2111593891u, 1889500026u, 1952343757u, 2552477408u, 2632100695u, 2443283854u, 2506133561u, 2334638140u, 2414271883u, 2191915858u, 2254759653u, 3190512472u, 3135915759u, 3081330742u, 3009969537u, 2905550212u, 2850959411u, 2762807018u, 2691435357u, 3560074640u, 3505614887u, 3719321342u, 3648080713u, 3342211916u, 3287746299u, 3467911202u, 3396681109u, 4063920168u, 4143685023u, 4223187782u, 4286162673u, 3779000052u, 3858754371u, 3904687514u, 3967668269u, 881225847u, 809987520u, 1023691545u, 969234094u, 662832811u, 591600412u, 771767749u, 717299826u, 311336399u, 374308984u, 453813921u, 533576470u, 25881363u, 88864420u, 134795389u, 214552010u, 2023205639u, 2086057648u, 1897238633u, 1976864222u, 1804852699u, 1867694188u, 1645340341u, 1724971778u, 1587496639u, 1516133128u, 1461550545u, 1406951526u, 1302016099u, 1230646740u, 1142491917u, 1087903418u, 2896545431u, 2825181984u, 2770861561u, 2716262478u, 3215044683u, 3143675388u, 3055782693u, 3001194130u, 2326604591u, 2389456536u, 2200899649u, 2280525302u, 2578013683u, 2640855108u, 2418763421u, 2498394922u, 3769900519u, 3832873040u, 3912640137u, 3992402750u, 4088425275u, 4151408268u, 4197601365u, 4277358050u, 3334271071u, 3263032808u, 3476998961u, 3422541446u, 3585640067u, 3514407732u, 3694837229u, 3640369242u, 1762451694u, 1842216281u, 1619975040u, 1682949687u, 2047383090u, 2127137669u, 1938468188u, 2001449195u, 1325665622u, 1271206113u, 1183200824u, 1111960463u, 1543535498u, 1489069629u, 1434599652u, 1363369299u, 622672798u, 568075817u, 748617968u, 677256519u, 907627842u, 853037301u, 1067152940u, 995781531u, 51762726u, 131386257u, 177728840u, 240578815u, 269590778u, 349224269u, 429104020u, 491947555u, 4046411278u, 4126034873u, 4172115296u, 4234965207u, 3794477266u, 3874110821u, 3953728444u, 4016571915u, 3609705398u, 3555108353u, 3735388376u, 3664026991u, 3290680682u, 3236090077u, 3449943556u, 3378572211u, 3174993278u, 3120533705u, 3032266256u, 2961025959u, 2923101090u, 2868635157u, 2813903052u, 2742672763u, 2604032198u, 2683796849u, 2461293480u, 2524268063u, 2284983834u, 2364738477u, 2175806836u, 2238787779u, 1569362073u, 1498123566u, 1409854455u, 1355396672u, 1317987909u, 1246755826u, 1192025387u, 1137557660u, 2072149281u, 2135122070u, 1912620623u, 1992383480u, 1753615357u, 1816598090u, 1627664531u, 1707420964u, 295390185u, 358241886u, 404320391u, 483945776u, 43990325u, 106832002u, 186451547u, 266083308u, 932423249u, 861060070u, 1041341759u, 986742920u, 613929101u, 542559546u, 756411363u, 701822548u, 3316196985u, 3244833742u, 3425377559u, 3370778784u, 3601682597u, 3530312978u, 3744426955u, 3689838204u, 3819031489u, 3881883254u, 3928223919u, 4007849240u, 4037393693u, 4100235434u, 4180117107u, 4259748804u, 2310601993u, 2373574846u, 2151335527u, 2231098320u, 2596047829u, 2659030626u, 2470359227u, 2550115596u, 2947551409u, 2876312838u, 2788305887u, 2733848168u, 3165939309u, 3094707162u, 3040238851u, 2985771188u }; private int globalCrc; public long Value => ~globalCrc; public StrangeCRC() { Reset(); } public void Reset() { globalCrc = -1; } public void Update(int inCh) { int num = (globalCrc >> 24) ^ inCh; if (num < 0) { num = 256 + num; } globalCrc = (int)((globalCrc << 8) ^ crc32Table[num]); } public void Update(byte[] buf) { Update(buf, 0, buf.Length); } public void Update(byte[] buf, int off, int len) { if (buf == null) { throw new ArgumentNullException("buf"); } if (off < 0 || len < 0 || off + len > buf.Length) { throw new ArgumentOutOfRangeException(); } for (int i = 0; i < len; i++) { Update(buf[off++]); } } } internal interface IChecksum { long Value { get; } void Reset(); void Update(int bval); void Update(byte[] buffer); void Update(byte[] buf, int off, int len); } internal sealed class Adler32 : IChecksum { private static readonly uint BASE = 65521u; private uint checksum; public long Value => checksum; public Adler32() { Reset(); } public void Reset() { checksum = 1u; } public void Update(int bval) { uint num = checksum & 0xFFFFu; uint num2 = checksum >> 16; num = (uint)((int)num + (bval & 0xFF)) % BASE; num2 = (num + num2) % BASE; checksum = (num2 << 16) + num; } public void Update(byte[] buffer) { Update(buffer, 0, buffer.Length); } public void Update(byte[] buf, int off, int len) { if (buf == null) { throw new ArgumentNullException("buf"); } if (off < 0 || len < 0 || off + len > buf.Length) { throw new ArgumentOutOfRangeException(); } uint num = checksum & 0xFFFFu; uint num2 = checksum >> 16; while (len > 0) { int num3 = 3800; if (num3 > len) { num3 = len; } len -= num3; while (--num3 >= 0) { num += (uint)(buf[off++] & 0xFF); num2 += num; } num %= BASE; num2 %= BASE; } checksum = (num2 << 16) | num; } } internal sealed class Crc32 : IChecksum { private static readonly uint CrcSeed = uint.MaxValue; private static readonly uint[] CrcTable = new uint[256] { 0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u, 3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u, 162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u, 4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u, 325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u, 4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u, 1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u, 3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u, 651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u, 3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u, 795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u, 2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u, 2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u, 2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u, 1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u, 2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u, 1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u, 2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u, 1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u, 3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u, 1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u, 3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u, 3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u, 225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u, 4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u, 426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u, 4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u, 953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u, 3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u, 829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u, 3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u, 733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u, 2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u, 1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u, 2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u, 1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u, 2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u, 1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u, 2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u, 1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u, 3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u, 1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u, 3020668471u, 3272380065u, 1510334235u, 755167117u }; private uint crc; public long Value { get { return crc; } set { crc = (uint)value; } } internal static uint ComputeCrc32(uint oldCrc, byte bval) { return CrcTable[(oldCrc ^ bval) & 0xFF] ^ (oldCrc >> 8); } public void Reset() { crc = 0u; } public void Update(int bval) { crc ^= CrcSeed; crc = CrcTable[(crc ^ bval) & 0xFF] ^ (crc >> 8); crc ^= CrcSeed; } public void Update(byte[] buffer) { Update(buffer, 0, buffer.Length); } public void Update(byte[] buf, int off, int len) { if (buf == null) { throw new ArgumentNullException("buf"); } if (off < 0 || len < 0 || off + len > buf.Length) { throw new ArgumentOutOfRangeException(); } crc ^= CrcSeed; while (--len >= 0) { crc = CrcTable[(crc ^ buf[off++]) & 0xFF] ^ (crc >> 8); } crc ^= CrcSeed; } } } namespace ICSharpCode.SharpZipLib.BZip2 { internal class BZip2InputStream : Stream { private const int START_BLOCK_STATE = 1; private const int RAND_PART_A_STATE = 2; private const int RAND_PART_B_STATE = 3; private const int RAND_PART_C_STATE = 4; private const int NO_RAND_PART_A_STATE = 5; private const int NO_RAND_PART_B_STATE = 6; private const int NO_RAND_PART_C_STATE = 7; private int last; private int origPtr; private int blockSize100k; private bool blockRandomised; private int bsBuff; private int bsLive; private IChecksum mCrc = new StrangeCRC(); private bool[] inUse = new bool[256]; private int nInUse; private byte[] seqToUnseq = new byte[256]; private byte[] unseqToSeq = new byte[256]; private byte[] selector = new byte[BZip2Constants.MAX_SELECTORS]; private byte[] selectorMtf = new byte[BZip2Constants.MAX_SELECTORS]; private int[] tt; private byte[] ll8; private int[] unzftab = new int[256]; private int[][] limit = new int[BZip2Constants.N_GROUPS][]; private int[][] baseArray = new int[BZip2Constants.N_GROUPS][]; private int[][] perm = new int[BZip2Constants.N_GROUPS][]; private int[] minLens = new int[BZip2Constants.N_GROUPS]; private Stream baseStream; private bool streamEnd; private int currentChar = -1; private int currentState = 1; private int storedBlockCRC; private int storedCombinedCRC; private int computedBlockCRC; private uint computedCombinedCRC; private int count; private int chPrev; private int ch2; private int tPos; private int rNToGo; private int rTPos; private int i2; private int j2; private byte z; public override bool CanRead => baseStream.CanRead; public override bool CanSeek => baseStream.CanSeek; public override bool CanWrite => false; public override long Length => baseStream.Length; public override long Position { get { return baseStream.Position; } set { throw new NotSupportedException("BZip2InputStream position cannot be set"); } } public BZip2InputStream(Stream stream) { for (int i = 0; i < BZip2Constants.N_GROUPS; i++) { limit[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; baseArray[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; perm[i] = new int[BZip2Constants.MAX_ALPHA_SIZE]; } ll8 = null; tt = null; BsSetStream(stream); Initialize(); InitBlock(); SetupBlock(); } public override void Flush() { if (baseStream != null) { baseStream.Flush(); } } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("BZip2InputStream Seek not supported"); } public override void SetLength(long val) { throw new NotSupportedException("BZip2InputStream SetLength not supported"); } public override void Write(byte[] array, int offset, int count) { throw new NotSupportedException("BZip2InputStream Write not supported"); } public override void WriteByte(byte val) { throw new NotSupportedException("BZip2InputStream WriteByte not supported"); } public override int Read(byte[] b, int offset, int count) { for (int i = 0; i < count; i++) { int num = ReadByte(); if (num == -1) { return i; } b[offset + i] = (byte)num; } return count; } public override void Close() { if (baseStream != null) { baseStream.Close(); } } private void MakeMaps() { nInUse = 0; for (int i = 0; i < 256; i++) { if (inUse[i]) { seqToUnseq[nInUse] = (byte)i; unseqToSeq[i] = (byte)nInUse; nInUse++; } } } public override int ReadByte() { if (streamEnd) { return -1; } int result = currentChar; switch (currentState) { case 3: SetupRandPartB(); break; case 4: SetupRandPartC(); break; case 6: SetupNoRandPartB(); break; case 7: SetupNoRandPartC(); break; } return result; } private void Initialize() { char c = BsGetUChar(); char c2 = BsGetUChar(); char c3 = BsGetUChar(); char c4 = BsGetUChar(); if (c != 'B' || c2 != 'Z' || c3 != 'h' || c4 < '1' || c4 > '9') { streamEnd = true; return; } SetDecompressStructureSizes(c4 - 48); computedCombinedCRC = 0u; } private void InitBlock() { char c = BsGetUChar(); char c2 = BsGetUChar(); char c3 = BsGetUChar(); char c4 = BsGetUChar(); char c5 = BsGetUChar(); char c6 = BsGetUChar(); if (c == '\u0017' && c2 == 'r' && c3 == 'E' && c4 == '8' && c5 == 'P' && c6 == '\u0090') { Complete(); return; } if (c != '1' || c2 != 'A' || c3 != 'Y' || c4 != '&' || c5 != 'S' || c6 != 'Y') { BadBlockHeader(); streamEnd = true; return; } storedBlockCRC = BsGetInt32(); blockRandomised = BsR(1) == 1; GetAndMoveToFrontDecode(); mCrc.Reset(); currentState = 1; } private void EndBlock() { computedBlockCRC = (int)mCrc.Value; if (storedBlockCRC != computedBlockCRC) { CrcError(); } computedCombinedCRC = ((computedCombinedCRC << 1) & 0xFFFFFFFFu) | (computedCombinedCRC >> 31); computedCombinedCRC ^= (uint)computedBlockCRC; } private void Complete() { storedCombinedCRC = BsGetInt32(); if (storedCombinedCRC != (int)computedCombinedCRC) { CrcError(); } streamEnd = true; } private static void CompressedStreamEOF() { throw new BZip2Exception("BZip2 input stream end of compressed stream"); } private static void BlockOverrun() { throw new BZip2Exception("BZip2 input stream block overrun"); } private static void BadBlockHeader() { throw new BZip2Exception("BZip2 input stream bad block header"); } private static void CrcError() { throw new BZip2Exception("BZip2 input stream crc error"); } private void BsSetStream(Stream f) { baseStream = f; bsLive = 0; bsBuff = 0; } private void FillBuffer() { int num = 0; try { num = baseStream.ReadByte(); } catch (Exception) { CompressedStreamEOF(); } if (num == -1) { CompressedStreamEOF(); } bsBuff = (bsBuff << 8) | (num & 0xFF); bsLive += 8; } private int BsR(int n) { while (bsLive < n) { FillBuffer(); } int result = (bsBuff >> bsLive - n) & ((1 << n) - 1); bsLive -= n; return result; } private char BsGetUChar() { return (char)BsR(8); } private int BsGetint() { int num = 0; num = (num << 8) | BsR(8); num = (num << 8) | BsR(8); num = (num << 8) | BsR(8); return (num << 8) | BsR(8); } private int BsGetIntVS(int numBits) { return BsR(numBits); } private int BsGetInt32() { return BsGetint(); } private void HbCreateDecodeTables(int[] limit, int[] baseArray, int[] perm, char[] length, int minLen, int maxLen, int alphaSize) { int num = 0; for (int i = minLen; i <= maxLen; i++) { for (int j = 0; j < alphaSize; j++) { if (length[j] == i) { perm[num] = j; num++; } } } for (int k = 0; k < BZip2Constants.MAX_CODE_LEN; k++) { baseArray[k] = 0; } for (int l = 0; l < alphaSize; l++) { baseArray[length[l] + 1]++; } for (int m = 1; m < BZip2Constants.MAX_CODE_LEN; m++) { baseArray[m] += baseArray[m - 1]; } for (int n = 0; n < BZip2Constants.MAX_CODE_LEN; n++) { limit[n] = 0; } int num2 = 0; for (int num3 = minLen; num3 <= maxLen; num3++) { num2 += baseArray[num3 + 1] - baseArray[num3]; limit[num3] = num2 - 1; num2 <<= 1; } for (int num4 = minLen + 1; num4 <= maxLen; num4++) { baseArray[num4] = (limit[num4 - 1] + 1 << 1) - baseArray[num4]; } } private void RecvDecodingTables() { char[][] array = new char[BZip2Constants.N_GROUPS][]; for (int i = 0; i < BZip2Constants.N_GROUPS; i++) { array[i] = new char[BZip2Constants.MAX_ALPHA_SIZE]; } bool[] array2 = new bool[16]; for (int j = 0; j < 16; j++) { array2[j] = BsR(1) == 1; } for (int k = 0; k < 16; k++) { if (array2[k]) { for (int l = 0; l < 16; l++) { inUse[k * 16 + l] = BsR(1) == 1; } } else { for (int m = 0; m < 16; m++) { inUse[k * 16 + m] = false; } } } MakeMaps(); int num = nInUse + 2; int num2 = BsR(3); int num3 = BsR(15); for (int n = 0; n < num3; n++) { int num4 = 0; while (BsR(1) == 1) { num4++; } selectorMtf[n] = (byte)num4; } byte[] array3 = new byte[BZip2Constants.N_GROUPS]; for (int num5 = 0; num5 < num2; num5++) { array3[num5] = (byte)num5; } for (int num6 = 0; num6 < num3; num6++) { int num7 = selectorMtf[num6]; byte b = array3[num7]; while (num7 > 0) { array3[num7] = array3[num7 - 1]; num7--; } array3[0] = b; selector[num6] = b; } for (int num8 = 0; num8 < num2; num8++) { int num9 = BsR(5); for (int num10 = 0; num10 < num; num10++) { while (BsR(1) == 1) { num9 = ((BsR(1) != 0) ? (num9 - 1) : (num9 + 1)); } array[num8][num10] = (char)num9; } } for (int num11 = 0; num11 < num2; num11++) { int num12 = 32; int num13 = 0; for (int num14 = 0; num14 < num; num14++) { num13 = Math.Max(num13, array[num11][num14]); num12 = Math.Min(num12, array[num11][num14]); } HbCreateDecodeTables(limit[num11], baseArray[num11], perm[num11], array[num11], num12, num13, num); minLens[num11] = num12; } } private void GetAndMoveToFrontDecode() { byte[] array = new byte[256]; int num = BZip2Constants.baseBlockSize * blockSize100k; origPtr = BsGetIntVS(24); RecvDecodingTables(); int num2 = nInUse + 1; int num3 = -1; int num4 = 0; for (int i = 0; i <= 255; i++) { unzftab[i] = 0; } for (int j = 0; j <= 255; j++) { array[j] = (byte)j; } last = -1; if (num4 == 0) { num3++; num4 = BZip2Constants.G_SIZE; } num4--; int num5 = selector[num3]; int num6 = minLens[num5]; int num7 = BsR(num6); while (num7 > limit[num5][num6]) { if (num6 > 20) { throw new BZip2Exception("Bzip data error"); } num6++; while (bsLive < 1) { FillBuffer(); } int num8 = (bsBuff >> bsLive - 1) & 1; bsLive--; num7 = (num7 << 1) | num8; } if (num7 - baseArray[num5][num6] < 0 || num7 - baseArray[num5][num6] >= BZip2Constants.MAX_ALPHA_SIZE) { throw new BZip2Exception("Bzip data error"); } int num9 = perm[num5][num7 - baseArray[num5][num6]]; while (num9 != num2) { if (num9 == BZip2Constants.RUNA || num9 == BZip2Constants.RUNB) { int num10 = -1; int num11 = 1; do { if (num9 == BZip2Constants.RUNA) { num10 += 1 * num11; } else if (num9 == BZip2Constants.RUNB) { num10 += 2 * num11; } num11 <<= 1; if (num4 == 0) { num3++; num4 = BZip2Constants.G_SIZE; } num4--; num5 = selector[num3]; num6 = minLens[num5]; num7 = BsR(num6); while (num7 > limit[num5][num6]) { num6++; while (bsLive < 1) { FillBuffer(); } int num8 = (bsBuff >> bsLive - 1) & 1; bsLive--; num7 = (num7 << 1) | num8; } num9 = perm[num5][num7 - baseArray[num5][num6]]; } while (num9 == BZip2Constants.RUNA || num9 == BZip2Constants.RUNB); num10++; byte b = seqToUnseq[array[0]]; unzftab[b] += num10; while (num10 > 0) { last++; ll8[last] = b; num10--; } if (last >= num) { BlockOverrun(); } continue; } last++; if (last >= num) { BlockOverrun(); } byte b2 = array[num9 - 1]; unzftab[seqToUnseq[b2]]++; ll8[last] = seqToUnseq[b2]; for (int num12 = num9 - 1; num12 > 0; num12--) { array[num12] = array[num12 - 1]; } array[0] = b2; if (num4 == 0) { num3++; num4 = BZip2Constants.G_SIZE; } num4--; num5 = selector[num3]; num6 = minLens[num5]; num7 = BsR(num6); while (num7 > limit[num5][num6]) { num6++; while (bsLive < 1) { FillBuffer(); } int num8 = (bsBuff >> bsLive - 1) & 1; bsLive--; num7 = (num7 << 1) | num8; } num9 = perm[num5][num7 - baseArray[num5][num6]]; } } private void SetupBlock() { int[] array = new int[257]; array[0] = 0; Array.Copy(unzftab, 0, array, 1, 256); for (int i = 1; i <= 256; i++) { array[i] += array[i - 1]; } for (int j = 0; j <= last; j++) { byte b = ll8[j]; tt[array[b]] = j; array[b]++; } array = null; tPos = tt[origPtr]; count = 0; i2 = 0; ch2 = 256; if (blockRandomised) { rNToGo = 0; rTPos = 0; SetupRandPartA(); } else { SetupNoRandPartA(); } } private void SetupRandPartA() { if (i2 <= last) { chPrev = ch2; ch2 = ll8[tPos]; tPos = tt[tPos]; if (rNToGo == 0) { rNToGo = BZip2Constants.rNums[rTPos]; rTPos++; if (rTPos == 512) { rTPos = 0; } } rNToGo--; ch2 ^= ((rNToGo == 1) ? 1 : 0); i2++; currentChar = ch2; currentState = 3; mCrc.Update(ch2); } else { EndBlock(); InitBlock(); SetupBlock(); } } private void SetupNoRandPartA() { if (i2 <= last) { chPrev = ch2; ch2 = ll8[tPos]; tPos = tt[tPos]; i2++; currentChar = ch2; currentState = 6; mCrc.Update(ch2); } else { EndBlock(); InitBlock(); SetupBlock(); } } private void SetupRandPartB() { if (ch2 != chPrev) { currentState = 2; count = 1; SetupRandPartA(); return; } count++; if (count >= 4) { z = ll8[tPos]; tPos = tt[tPos]; if (rNToGo == 0) { rNToGo = BZip2Constants.rNums[rTPos]; rTPos++; if (rTPos == 512) { rTPos = 0; } } rNToGo--; z ^= ((rNToGo == 1) ? ((byte)1) : ((byte)0)); j2 = 0; currentState = 4; SetupRandPartC(); } else { currentState = 2; SetupRandPartA(); } } private void SetupRandPartC() { if (j2 < z) { currentChar = ch2; mCrc.Update(ch2); j2++; } else { currentState = 2; i2++; count = 0; SetupRandPartA(); } } private void SetupNoRandPartB() { if (ch2 != chPrev) { currentState = 5; count = 1; SetupNoRandPartA(); return; } count++; if (count >= 4) { z = ll8[tPos]; tPos = tt[tPos]; currentState = 7; j2 = 0; SetupNoRandPartC(); } else { currentState = 5; SetupNoRandPartA(); } } private void SetupNoRandPartC() { if (j2 < z) { currentChar = ch2; mCrc.Update(ch2); j2++; } else { currentState = 5; i2++; count = 0; SetupNoRandPartA(); } } private void SetDecompressStructureSizes(int newSize100k) { if (0 > newSize100k || newSize100k > 9 || 0 > blockSize100k || blockSize100k > 9) { throw new BZip2Exception("Invalid block size"); } blockSize100k = newSize100k; if (newSize100k != 0) { int num = BZip2Constants.baseBlockSize * newSize100k; ll8 = new byte[num]; tt = new int[num]; } } } internal sealed class BZip2Constants { public static readonly int[] rNums = new int[512] { 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 936, 638 }; public static readonly int baseBlockSize = 100000; public static readonly int MAX_ALPHA_SIZE = 258; public static readonly int MAX_CODE_LEN = 23; public static readonly int RUNA = 0; public static readonly int RUNB = 1; public static readonly int N_GROUPS = 6; public static readonly int G_SIZE = 50; public static readonly int N_ITERS = 4; public static readonly int MAX_SELECTORS = 2 + 900000 / G_SIZE; public static readonly int NUM_OVERSHOOT_BYTES = 20; private BZip2Constants() { } } internal class BZip2OutputStream : Stream { private class StackElem { public int ll; public int hh; public int dd; } private static readonly int SETMASK = 2097152; private static readonly int CLEARMASK = ~SETMASK; private static readonly int GREATER_ICOST = 15; private static readonly int LESSER_ICOST = 0; private static readonly int SMALL_THRESH = 20; private static readonly int DEPTH_THRESH = 10; private static readonly int QSORT_STACK_SIZE = 1000; private int last; private int origPtr; private int blockSize100k; private bool blockRandomised; private int bytesOut; private int bsBuff; private int bsLive; private IChecksum mCrc = new StrangeCRC(); private bool[] inUse = new bool[256]; private int nInUse; private char[] seqToUnseq = new char[256]; private char[] unseqToSeq = new char[256]; private char[] selector = new char[BZip2Constants.MAX_SELECTORS]; private char[] selectorMtf = new char[BZip2Constants.MAX_SELECTORS]; private byte[] block; private int[] quadrant; private int[] zptr; private short[] szptr; private int[] ftab; private int nMTF; private int[] mtfFreq = new int[BZip2Constants.MAX_ALPHA_SIZE]; private int workFactor; private int workDone; private int workLimit; private bool firstAttempt; private int nBlocksRandomised; private int currentChar = -1; private int runLength; private bool closed; private uint blockCRC; private uint combinedCRC; private int allowableBlockSize; private Stream baseStream; private readonly int[] incs = new int[14] { 1, 4, 13, 40, 121, 364, 1093, 3280, 9841, 29524, 88573, 265720, 797161, 2391484 }; public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => baseStream.CanWrite; public override long Length => baseStream.Length; public override long Position { get { return baseStream.Position; } set { throw new NotSupportedException("BZip2OutputStream position cannot be set"); } } public BZip2OutputStream(Stream stream) : this(stream, 9) { } public BZip2OutputStream(Stream stream, int blockSize) { block = null; quadrant = null; zptr = null; ftab = null; BsSetStream(stream); workFactor = 50; if (blockSize > 9) { blockSize = 9; } if (blockSize < 1) { blockSize = 1; } blockSize100k = blockSize; AllocateCompressStructures(); Initialize(); InitBlock(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("BZip2OutputStream Seek not supported"); } public override void SetLength(long val) { throw new NotSupportedException("BZip2OutputStream SetLength not supported"); } public override int ReadByte() { throw new NotSupportedException("BZip2OutputStream ReadByte not supported"); } public override int Read(byte[] b, int off, int len) { throw new NotSupportedException("BZip2OutputStream Read not supported"); } public override void Write(byte[] buf, int off, int len) { for (int i = 0; i < len; i++) { WriteByte(buf[off + i]); } } private static void Panic() { throw new BZip2Exception("BZip2 output stream panic"); } private void MakeMaps() { nInUse = 0; for (int i = 0; i < 256; i++) { if (inUse[i]) { seqToUnseq[nInUse] = (char)i; unseqToSeq[i] = (char)nInUse; nInUse++; } } } private static void HbMakeCodeLengths(char[] len, int[] freq, int alphaSize, int maxLen) { int[] array = new int[BZip2Constants.MAX_ALPHA_SIZE + 2]; int[] array2 = new int[BZip2Constants.MAX_ALPHA_SIZE * 2]; int[] array3 = new int[BZip2Constants.MAX_ALPHA_SIZE * 2]; for (int i = 0; i < alphaSize; i++) { array2[i + 1] = ((freq[i] == 0) ? 1 : freq[i]) << 8; } while (true) { int num = alphaSize; int num2 = 0; array[0] = 0; array2[0] = 0; array3[0] = -2; for (int j = 1; j <= alphaSize; j++) { array3[j] = -1; num2++; array[num2] = j; int num3 = num2; int num4 = array[num3]; while (array2[num4] < array2[array[num3 >> 1]]) { array[num3] = array[num3 >> 1]; num3 >>= 1; } array[num3] = num4; } if (num2 >= BZip2Constants.MAX_ALPHA_SIZE + 2) { Panic(); } while (num2 > 1) { int num5 = array[1]; array[1] = array[num2]; num2--; int num6 = 1; int num7 = 0; int num8 = array[num6]; while (true) { num7 = num6 << 1; if (num7 > num2) { break; } if (num7 < num2 && array2[array[num7 + 1]] < array2[array[num7]]) { num7++; } if (array2[num8] < array2[array[num7]]) { break; } array[num6] = array[num7]; num6 = num7; } array[num6] = num8; int num9 = array[1]; array[1] = array[num2]; num2--; num6 = 1; num7 = 0; num8 = array[num6]; while (true) { num7 = num6 << 1; if (num7 > num2) { break; } if (num7 < num2 && array2[array[num7 + 1]] < array2[array[num7]]) { num7++; } if (array2[num8] < array2[array[num7]]) { break; } array[num6] = array[num7]; num6 = num7; } array[num6] = num8; num++; array3[num5] = (array3[num9] = num); array2[num] = (int)((array2[num5] & 0xFFFFFF00L) + (array2[num9] & 0xFFFFFF00L)) | (1 + (((array2[num5] & 0xFF) <= (array2[num9] & 0xFF)) ? (array2[num9] & 0xFF) : (array2[num5] & 0xFF))); array3[num] = -1; num2++; array[num2] = num; num6 = num2; num8 = array[num6]; while (array2[num8] < array2[array[num6 >> 1]]) { array[num6] = array[num6 >> 1]; num6 >>= 1; } array[num6] = num8; } if (num >= BZip2Constants.MAX_ALPHA_SIZE * 2) { Panic(); } bool flag = false; for (int k = 1; k <= alphaSize; k++) { int num10 = 0; int num11 = k; while (array3[num11] >= 0) { num11 = array3[num11]; num10++; } len[k - 1] = (char)num10; if (num10 > maxLen) { flag = true; } } if (!flag) { break; } for (int l = 1; l < alphaSize; l++) { int num10 = array2[l] >> 8; num10 = 1 + num10 / 2; array2[l] = num10 << 8; } } } public override void WriteByte(byte bv) { int num = (256 + bv) % 256; if (currentChar != -1) { if (currentChar == num) { runLength++; if (runLength > 254) { WriteRun(); currentChar = -1; runLength = 0; } } else { WriteRun(); runLength = 1; currentChar = num; } } else { currentChar = num; runLength++; } } private void WriteRun() { if (last < allowableBlockSize) { inUse[currentChar] = true; for (int i = 0; i < runLength; i++) { mCrc.Update(currentChar); } switch (runLength) { case 1: last++; block[last + 1] = (byte)currentChar; break; case 2: last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; break; case 3: last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; break; default: inUse[runLength - 4] = true; last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)currentChar; last++; block[last + 1] = (byte)(runLength - 4); break; } } else { EndBlock(); InitBlock(); WriteRun(); } } ~BZip2OutputStream() { Close(); } public override void Close() { if (!closed) { closed = true; if (runLength > 0) { WriteRun(); } currentChar = -1; EndBlock(); EndCompression(); Flush(); baseStream.Close(); } } public override void Flush() { baseStream.Flush(); } private void Initialize() { bytesOut = 0; nBlocksRandomised = 0; BsPutUChar(66); BsPutUChar(90); BsPutUChar(104); BsPutUChar(48 + blockSize100k); combinedCRC = 0u; } private void InitBlock() { mCrc.Reset(); last = -1; for (int i = 0; i < 256; i++) { inUse[i] = false; } allowableBlockSize = BZip2Constants.baseBlockSize * blockSize100k - 20; } private void EndBlock() { if (last >= 0) { blockCRC = (uint)mCrc.Value; combinedCRC = (combinedCRC << 1) | (combinedCRC >> 31); combinedCRC ^= blockCRC; DoReversibleTransformation(); BsPutUChar(49); BsPutUChar(65); BsPutUChar(89); BsPutUChar(38); BsPutUChar(83); BsPutUChar(89); BsPutint((int)blockCRC); if (blockRandomised) { BsW(1, 1); nBlocksRandomised++; } else { BsW(1, 0); } MoveToFrontCodeAndSend(); } } private void EndCompression() { BsPutUChar(23); BsPutUChar(114); BsPutUChar(69); BsPutUChar(56); BsPutUChar(80); BsPutUChar(144); BsPutint((int)combinedCRC); BsFinishedWithStream(); } private void HbAssignCodes(int[] code, char[] length, int minLen, int maxLen, int alphaSize) { int num = 0; for (int i = minLen; i <= maxLen; i++) { for (int j = 0; j < alphaSize; j++) { if (length[j] == i) { code[j] = num; num++; } } num <<= 1; } } private void BsSetStream(Stream f) { baseStream = f; bsLive = 0; bsBuff = 0; bytesOut = 0; } private void BsFinishedWithStream() { while (bsLive > 0) { int num = bsBuff >> 24; baseStream.WriteByte((byte)num); bsBuff <<= 8; bsLive -= 8; bytesOut++; } } private void BsW(int n, int v) { while (bsLive >= 8) { int num = bsBuff >> 24; baseStream.WriteByte((byte)num); bsBuff <<= 8; bsLive -= 8; bytesOut++; } bsBuff |= v << 32 - bsLive - n; bsLive += n; } private void BsPutUChar(int c) { BsW(8, c); } private void BsPutint(int u) { BsW(8, (u >> 24) & 0xFF); BsW(8, (u >> 16) & 0xFF); BsW(8, (u >> 8) & 0xFF); BsW(8, u & 0xFF); } private void BsPutIntVS(int numBits, int c) { BsW(numBits, c); } private void SendMTFValues() { char[][] array = new char[BZip2Constants.N_GROUPS][]; for (int i = 0; i < BZip2Constants.N_GROUPS; i++) { array[i] = new char[BZip2Constants.MAX_ALPHA_SIZE]; } int num = 0; int num2 = nInUse + 2; for (int j = 0; j < BZip2Constants.N_GROUPS; j++) { for (int k = 0; k < num2; k++) { array[j][k] = (char)GREATER_ICOST; } } if (nMTF <= 0) { Panic(); } int num3 = ((nMTF < 200) ? 2 : ((nMTF < 600) ? 3 : ((nMTF < 1200) ? 4 : ((nMTF >= 2400) ? 6 : 5)))); int num4 = num3; int num5 = nMTF; int num6 = 0; while (num4 > 0) { int num7 = num5 / num4; int l = 0; int num8; for (num8 = num6 - 1; l < num7; l += mtfFreq[num8]) { if (num8 >= num2 - 1) { break; } num8++; } if (num8 > num6 && num4 != num3 && num4 != 1 && (num3 - num4) % 2 == 1) { l -= mtfFreq[num8]; num8--; } for (int m = 0; m < num2; m++) { if (m >= num6 && m <= num8) { array[num4 - 1][m] = (char)LESSER_ICOST; } else { array[num4 - 1][m] = (char)GREATER_ICOST; } } num4--; num6 = num8 + 1; num5 -= l; } int[][] array2 = new int[BZip2Constants.N_GROUPS][]; for (int n = 0; n < BZip2Constants.N_GROUPS; n++) { array2[n] = new int[BZip2Constants.MAX_ALPHA_SIZE]; } int[] array3 = new int[BZip2Constants.N_GROUPS]; short[] array4 = new short[BZip2Constants.N_GROUPS]; for (int num9 = 0; num9 < BZip2Constants.N_ITERS; num9++) { for (int num10 = 0; num10 < num3; num10++) { array3[num10] = 0; } for (int num11 = 0; num11 < num3; num11++) { for (int num12 = 0; num12 < num2; num12++) { array2[num11][num12] = 0; } } num = 0; int num13 = 0; num6 = 0; while (num6 < nMTF) { int num8 = num6 + BZip2Constants.G_SIZE - 1; if (num8 >= nMTF) { num8 = nMTF - 1; } for (int num14 = 0; num14 < num3; num14++) { array4[num14] = 0; } if (num3 == 6) { short num15 = 0; short num16 = num15; num15 = num15; short num17 = num15; num15 = num15; short num18 = num15; num15 = num15; short num19 = num15; num15 = num15; short num20 = num15; short num21 = num15; for (int num22 = num6; num22 <= num8; num22++) { short num23 = szptr[num22]; num21 += (short)array[0][num23]; num20 += (short)array[1][num23]; num19 += (short)array[2][num23]; num18 += (short)array[3][num23]; num17 += (short)array[4][num23]; num16 += (short)array[5][num23]; } array4[0] = num21; array4[1] = num20; array4[2] = num19; array4[3] = num18; array4[4] = num17; array4[5] = num16; } else { for (int num24 = num6; num24 <= num8; num24++) { short num25 = szptr[num24]; for (int num26 = 0; num26 < num3; num26++) { array4[num26] += (short)array[num26][num25]; } } } int num27 = 999999999; int num28 = -1; for (int num29 = 0; num29 < num3; num29++) { if (array4[num29] < num27) { num27 = array4[num29]; num28 = num29; } } num13 += num27; array3[num28]++; selector[num] = (char)num28; num++; for (int num30 = num6; num30 <= num8; num30++) { array2[num28][szptr[num30]]++; } num6 = num8 + 1; } for (int num31 = 0; num31 < num3; num31++) { HbMakeCodeLengths(array[num31], array2[num31], num2, 20); } } array2 = null; array3 = null; array4 = null; if (num3 >= 8) { Panic(); } if (num >= 32768 || num > 2 + 900000 / BZip2Constants.G_SIZE) { Panic(); } char[] array5 = new char[BZip2Constants.N_GROUPS]; for (int num32 = 0; num32 < num3; num32++) { array5[num32] = (char)num32; } for (int num33 = 0; num33 < num; num33++) { char c = selector[num33]; int num34 = 0; char c2 = array5[num34]; while (c != c2) { num34++; char c3 = c2; c2 = array5[num34]; array5[num34] = c3; } array5[0] = c2; selectorMtf[num33] = (char)num34; } int[][] array6 = new int[BZip2Constants.N_GROUPS][]; for (int num35 = 0; num35 < BZip2Constants.N_GROUPS; num35++) { array6[num35] = new int[BZip2Constants.MAX_ALPHA_SIZE]; } for (int num36 = 0; num36 < num3; num36++) { int num37 = 32; int num38 = 0; for (int num39 = 0; num39 < num2; num39++) { if (array[num36][num39] > num38) { num38 = array[num36][num39]; } if (array[num36][num39] < num37) { num37 = array[num36][num39]; } } if (num38 > 20) { Panic(); } if (num37 < 1) { Panic(); } HbAssignCodes(array6[num36], array[num36], num37, num38, num2); } bool[] array7 = new bool[16]; for (int num40 = 0; num40 < 16; num40++) { array7[num40] = false; for (int num41 = 0; num41 < 16; num41++) { if (inUse[num40 * 16 + num41]) { array7[num40] = true; } } } int num42 = bytesOut; for (int num43 = 0; num43 < 16; num43++) { if (array7[num43]) { BsW(1, 1); } else { BsW(1, 0); } } for (int num44 = 0; num44 < 16; num44++) { if (!array7[num44]) { continue; } for (int num45 = 0; num45 < 16; num45++) { if (inUse[num44 * 16 + num45]) { BsW(1, 1); } else { BsW(1, 0); } } } num42 = bytesOut; BsW(3, num3); BsW(15, num); for (int num46 = 0; num46 < num; num46++) { for (int num47 = 0; num47 < selectorMtf[num46]; num47++) { BsW(1, 1); } BsW(1, 0); } num42 = bytesOut; for (int num48 = 0; num48 < num3; num48++) { int num49 = array[num48][0]; BsW(5, num49); for (int num50 = 0; num50 < num2; num50++) { for (; num49 < array[num48][num50]; num49++) { BsW(2, 2); } while (num49 > array[num48][num50]) { BsW(2, 3); num49--; } BsW(1, 0); } } num42 = bytesOut; int num51 = 0; num6 = 0; while (num6 < nMTF) { int num8 = num6 + BZip2Constants.G_SIZE - 1; if (num8 >= nMTF) { num8 = nMTF - 1; } for (int num52 = num6; num52 <= num8; num52++) { BsW(array[(uint)selector[num51]][szptr[num52]], array6[(uint)selector[num51]][szptr[num52]]); } num6 = num8 + 1; num51++; } if (num51 != num) { Panic(); } } private void MoveToFrontCodeAndSend() { BsPutIntVS(24, origPtr); GenerateMTFValues(); SendMTFValues(); } private void SimpleSort(int lo, int hi, int d) { int num = hi - lo + 1; if (num < 2) { return; } int i; for (i = 0; incs[i] < num; i++) { } for (i--; i >= 0; i--) { int num2 = incs[i]; int num3 = lo + num2; while (num3 <= hi) { int num4 = zptr[num3]; int num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (num3 > hi) { break; } num4 = zptr[num3]; num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (num3 > hi) { break; } num4 = zptr[num3]; num5 = num3; while (FullGtU(zptr[num5 - num2] + d, num4 + d)) { zptr[num5] = zptr[num5 - num2]; num5 -= num2; if (num5 <= lo + num2 - 1) { break; } } zptr[num5] = num4; num3++; if (workDone > workLimit && firstAttempt) { return; } } } } private void Vswap(int p1, int p2, int n) { int num = 0; while (n > 0) { num = zptr[p1]; zptr[p1] = zptr[p2]; zptr[p2] = num; p1++; p2++; n--; } } private byte Med3(byte a, byte b, byte c) { if (a > b) { byte b2 = a; a = b; b = b2; } if (b > c) { byte b2 = b; b = c; c = b2; } if (a > b) { b = a; } return b; } private void QSort3(int loSt, int hiSt, int dSt) { StackElem[] array = new StackElem[QSORT_STACK_SIZE]; for (int i = 0; i < QSORT_STACK_SIZE; i++) { array[i] = new StackElem(); } int num = 0; array[num].ll = loSt; array[num].hh = hiSt; array[num].dd = dSt; num++; while (num > 0) { if (num >= QSORT_STACK_SIZE) { Panic(); } num--; int ll = array[num].ll; int hh = array[num].hh; int dd = array[num].dd; if (hh - ll < SMALL_THRESH || dd > DEPTH_THRESH) { SimpleSort(ll, hh, dd); if (workDone > workLimit && firstAttempt) { break; } continue; } int num2 = Med3(block[zptr[ll] + dd + 1], block[zptr[hh] + dd + 1], block[zptr[ll + hh >> 1] + dd + 1]); int num3 = ll; int num4 = num3; int num5 = num3; num3 = hh; int num6 = num3; int num7 = num3; int num8; while (true) { if (num5 <= num7) { num8 = block[zptr[num5] + dd + 1] - num2; if (num8 == 0) { int num9 = 0; num9 = zptr[num5]; zptr[num5] = zptr[num4]; zptr[num4] = num9; num4++; num5++; continue; } if (num8 <= 0) { num5++; continue; } } while (num5 <= num7) { num8 = block[zptr[num7] + dd + 1] - num2; if (num8 == 0) { int num10 = 0; num10 = zptr[num7]; zptr[num7] = zptr[num6]; zptr[num6] = num10; num6--; num7--; } else { if (num8 < 0) { break; } num7--; } } if (num5 > num7) { break; } int num11 = zptr[num5]; zptr[num5] = zptr[num7]; zptr[num7] = num11; num5++; num7--; } if (num6 < num4) { array[num].ll = ll; array[num].hh = hh; array[num].dd = dd + 1; num++; continue; } num8 = ((num4 - ll >= num5 - num4) ? (num5 - num4) : (num4 - ll)); Vswap(ll, num5 - num8, num8); int num12 = ((hh - num6 >= num6 - num7) ? (num6 - num7) : (hh - num6)); Vswap(num5, hh - num12 + 1, num12); num8 = ll + num5 - num4 - 1; num12 = hh - (num6 - num7) + 1; array[num].ll = ll; array[num].hh = num8; array[num].dd = dd; num++; array[num].ll = num8 + 1; array[num].hh = num12 - 1; array[num].dd = dd + 1; num++; array[num].ll = num12; array[num].hh = hh; array[num].dd = dd; num++; } } private void MainSort() { int[] array = new int[256]; int[] array2 = new int[256]; bool[] array3 = new bool[256]; for (int i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { block[last + i + 2] = block[i % (last + 1) + 1]; } for (int i = 0; i <= last + BZip2Constants.NUM_OVERSHOOT_BYTES; i++) { quadrant[i] = 0; } block[0] = block[last + 1]; if (last < 4000) { for (int i = 0; i <= last; i++) { zptr[i] = i; } firstAttempt = false; workLimit = 0; workDone = 0; SimpleSort(0, last, 0); return; } int num = 0; for (int i = 0; i <= 255; i++) { array3[i] = false; } for (int i = 0; i <= 65536; i++) { ftab[i] = 0; } int num2 = block[0]; for (int i = 0; i <= last; i++) { int num3 = block[i + 1]; ftab[(num2 << 8) + num3]++; num2 = num3; } for (int i = 1; i <= 65536; i++) { ftab[i] += ftab[i - 1]; } num2 = block[1]; int num4; for (int i = 0; i < last; i++) { int num3 = block[i + 2]; num4 = (num2 << 8) + num3; num2 = num3; ftab[num4]--; zptr[ftab[num4]] = i; } num4 = (block[last + 1] << 8) + block[1]; ftab[num4]--; zptr[ftab[num4]] = last; for (int i = 0; i <= 255; i++) { array[i] = i; } int num5 = 1; do { num5 = 3 * num5 + 1; } while (num5 <= 256); do { num5 /= 3; for (int i = num5; i <= 255; i++) { int num6 = array[i]; num4 = i; while (ftab[array[num4 - num5] + 1 << 8] - ftab[array[num4 - num5] << 8] > ftab[num6 + 1 << 8] - ftab[num6 << 8]) { array[num4] = array[num4 - num5]; num4 -= num5; if (num4 <= num5 - 1) { break; } } array[num4] = num6; } } while (num5 != 1); for (int i = 0; i <= 255; i++) { int num7 = array[i]; for (num4 = 0; num4 <= 255; num4++) { int num8 = (num7 << 8) + num4; if ((ftab[num8] & SETMASK) == SETMASK) { continue; } int num9 = ftab[num8] & CLEARMASK; int num10 = (ftab[num8 + 1] & CLEARMASK) - 1; if (num10 > num9) { QSort3(num9, num10, 2); num += num10 - num9 + 1; if (workDone > workLimit && firstAttempt) { return; } } ftab[num8] |= SETMASK; } array3[num7] = true; if (i < 255) { int num11 = ftab[num7 << 8] & CLEARMASK; int num12 = (ftab[num7 + 1 << 8] & CLEARMASK) - num11; int j; for (j = 0; num12 >> j > 65534; j++) { } for (num4 = 0; num4 < num12; num4++) { int num13 = zptr[num11 + num4]; int num14 = num4 >> j; quadrant[num13] = num14; if (num13 < BZip2Constants.NUM_OVERSHOOT_BYTES) { quadrant[num13 + last + 1] = num14; } } if (num12 - 1 >> j > 65535) { Panic(); } } for (num4 = 0; num4 <= 255; num4++) { array2[num4] = ftab[(num4 << 8) + num7] & CLEARMASK; } for (num4 = ftab[num7 << 8] & CLEARMASK; num4 < (ftab[num7 + 1 << 8] & CLEARMASK); num4++) { num2 = block[zptr[num4]]; if (!array3[num2]) { zptr[array2[num2]] = ((zptr[num4] != 0) ? (zptr[num4] - 1) : last); array2[num2]++; } } for (num4 = 0; num4 <= 255; num4++) { ftab[(num4 << 8) + num7] |= SETMASK; } } } private void RandomiseBlock() { int num = 0; int num2 = 0; for (int i = 0; i < 256; i++) { inUse[i] = false; } for (int i = 0; i <= last; i++) { if (num == 0) { num = BZip2Constants.rNums[num2]; num2++; if (num2 == 512) { num2 = 0; } } num--; block[i + 1] ^= ((num == 1) ? ((byte)1) : ((byte)0)); block[i + 1] &= byte.MaxValue; inUse[block[i + 1]] = true; } } private void DoReversibleTransformation() { workLimit = workFactor * last; workDone = 0; blockRandomised = false; firstAttempt = true; MainSort(); if (workDone > workLimit && firstAttempt) { RandomiseBlock(); workDone = 0; workLimit = 0; blockRandomised = true; firstAttempt = false; MainSort(); } origPtr = -1; for (int i = 0; i <= last; i++) { if (zptr[i] == 0) { origPtr = i; break; } } if (origPtr == -1) { Panic(); } } private bool FullGtU(int i1, int i2) { byte b = block[i1 + 1]; byte b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } i1++; i2++; int num = last + 1; do { b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } int num2 = quadrant[i1]; int num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; b = block[i1 + 1]; b2 = block[i2 + 1]; if (b != b2) { return b > b2; } num2 = quadrant[i1]; num3 = quadrant[i2]; if (num2 != num3) { return num2 > num3; } i1++; i2++; if (i1 > last) { i1 -= last; i1--; } if (i2 > last) { i2 -= last; i2--; } num -= 4; workDone++; } while (num >= 0); return false; } private void AllocateCompressStructures() { int num = BZip2Constants.baseBlockSize * blockSize100k; block = new byte[num + 1 + BZip2Constants.NUM_OVERSHOOT_BYTES]; quadrant = new int[num + BZip2Constants.NUM_OVERSHOOT_BYTES]; zptr = new int[num]; ftab = new int[65537]; if (block == null || quadrant == null || zptr == null || ftab == null) { } szptr = new short[2 * num]; } private void GenerateMTFValues() { char[] array = new char[256]; MakeMaps(); int num = nInUse + 1; for (int i = 0; i <= num; i++) { mtfFreq[i] = 0; } int num2 = 0; int num3 = 0; for (int i = 0; i < nInUse; i++) { array[i] = (char)i; } for (int i = 0; i <= last; i++) { char c = unseqToSeq[block[zptr[i]]]; int num4 = 0; char c2 = array[num4]; while (c != c2) { num4++; char c3 = c2; c2 = array[num4]; array[num4] = c3; } array[0] = c2; if (num4 == 0) { num3++; continue; } if (num3 > 0) { num3--; while (true) { switch (num3 % 2) { case 0: szptr[num2] = (short)BZip2Constants.RUNA; num2++; mtfFreq[BZip2Constants.RUNA]++; break; case 1: szptr[num2] = (short)BZip2Constants.RUNB; num2++; mtfFreq[BZip2Constants.RUNB]++; break; } if (num3 < 2) { break; } num3 = (num3 - 2) / 2; } num3 = 0; } szptr[num2] = (short)(num4 + 1); num2++; mtfFreq[num4 + 1]++; } if (num3 > 0) { num3--; while (true) { switch (num3 % 2) { case 0: szptr[num2] = (short)BZip2Constants.RUNA; num2++; mtfFreq[BZip2Constants.RUNA]++; break; case 1: szptr[num2] = (short)BZip2Constants.RUNB; num2++; mtfFreq[BZip2Constants.RUNB]++; break; } if (num3 < 2) { break; } num3 = (num3 - 2) / 2; } } szptr[num2] = (short)num; num2++; mtfFreq[num]++; nMTF = num2; } } internal class BZip2Exception : SharpZipBaseException { public BZip2Exception() { } public BZip2Exception(string message) : base(message) { } } internal sealed class BZip2 { public static void Decompress(Stream instream, Stream outstream) { BZip2InputStream bZip2InputStream = new BZip2InputStream(instream); for (int num = bZip2InputStream.ReadByte(); num != -1; num = bZip2InputStream.ReadByte()) { outstream.WriteByte((byte)num); } outstream.Flush(); } public static void Compress(Stream instream, Stream outstream, int blockSize) { int num = instream.ReadByte(); BZip2OutputStream bZip2OutputStream = new BZip2OutputStream(outstream, blockSize); while (num != -1) { bZip2OutputStream.WriteByte((byte)num); num = instream.ReadByte(); } instream.Close(); bZip2OutputStream.Close(); } } } namespace ICSharpCode.SharpZipLib.Tar { internal class InvalidHeaderException : TarException { public InvalidHeaderException() { } public InvalidHeaderException(string msg) : base(msg) { } } internal class TarHeader : ICloneable { public const int CHKSUMOFS = 148; public const byte LF_OLDNORM = 0; public const byte LF_NORMAL = 48; public const byte LF_LINK = 49; public const byte LF_SYMLINK = 50; public const byte LF_CHR = 51; public const byte LF_BLK = 52; public const byte LF_DIR = 53; public const byte LF_FIFO = 54; public const byte LF_CONTIG = 55; public const byte LF_GHDR = 103; public const byte LF_ACL = 65; public const byte LF_GNU_DUMPDIR = 68; public const byte LF_EXTATTR = 69; public const byte LF_META = 73; public const byte LF_GNU_LONGLINK = 75; public const byte LF_GNU_LONGNAME = 76; public const byte LF_GNU_MULTIVOL = 77; public const byte LF_GNU_NAMES = 78; public const byte LF_GNU_SPARSE = 83; public const byte LF_GNU_VOLHDR = 86; public static readonly int NAMELEN = 100; public static readonly int MODELEN = 8; public static readonly int UIDLEN = 8; public static readonly int GIDLEN = 8; public static readonly int CHKSUMLEN = 8; public static readonly int SIZELEN = 12; public static readonly int MAGICLEN = 6; public static readonly int VERSIONLEN = 2; public static readonly int MODTIMELEN = 12; public static readonly int UNAMELEN = 32; public static readonly int GNAMELEN = 32; public static readonly int DEVLEN = 8; public static readonly byte LF_XHDR = 120; public static readonly string TMAGIC = "ustar "; public static readonly string GNU_TMAGIC = "ustar "; private string name; private int mode; private int userId; private int groupId; private long size; private DateTime modTime; private int checksum; private bool isChecksumValid; private byte typeFlag; private string linkName; private string magic; private string version; private string userName; private string groupName; private int devMajor; private int devMinor; internal static int userIdAsSet = 0; internal static int groupIdAsSet = 0; internal static string userNameAsSet = null; internal static string groupNameAsSet = "None"; internal static int defaultUserId = 0; internal static int defaultGroupId = 0; internal static string defaultGroupName = "None"; internal static string defaultUser = null; private static readonly long timeConversionFactor = 10000000L; private static readonly DateTime dateTime1970 = new DateTime(1970, 1, 1, 0, 0, 0, 0); public string Name { get { return name; } set { if (value == null) { throw new ArgumentNullException(); } name = value; } } public int Mode { get { return mode; } set { mode = value; } } public int UserId { get { return userId; } set { userId = value; } } public int GroupId { get { return groupId; } set { groupId = value; } } public long Size { get { return size; } set { if (value < 0) { throw new ArgumentOutOfRangeException(); } size = value; } } public DateTime ModTime { get { return modTime; } set { if (value < dateTime1970) { throw new ArgumentOutOfRangeException(); } ref DateTime reference = ref modTime; reference = new DateTime(value.Year, value.Month, value.Day, value.Hour, value.Minute, value.Second); } } public int Checksum => checksum; public bool IsChecksumValid => isChecksumValid; public byte TypeFlag { get { return typeFlag; } set { typeFlag = value; } } public string LinkName { get { return linkName; } set { if (value == null) { throw new ArgumentNullException(); } linkName = value; } } public string Magic { get { return magic; } set { if (value == null) { throw new ArgumentNullException(); } magic = value; } } public string Version { get { return version; } set { if (value == null) { throw new ArgumentNullException(); } version = value; } } public string UserName { get { return userName; } set { if (value != null) { userName = value.Substring(0, Math.Min(UNAMELEN, value.Length)); return; } string text = Environment.UserName; if (text.Length > UNAMELEN) { text = text.Substring(0, UNAMELEN); } userName = text; } } public string GroupName { get { return groupName; } set { if (value == null) { groupName = "None"; } else { groupName = value; } } } public int DevMajor { get { return devMajor; } set { devMajor = value; } } public int DevMinor { get { return devMinor; } set { devMinor = value; } } public TarHeader() { Magic = TMAGIC; Version = " "; Name = ""; LinkName = ""; UserId = defaultUserId; GroupId = defaultGroupId; UserName = defaultUser; GroupName = defaultGroupName; Size = 0L; } static TarHeader() { dateTime1970 = dateTime1970; } internal static void RestoreSetValues() { defaultUserId = userIdAsSet; defaultUser = userNameAsSet; defaultGroupId = groupIdAsSet; defaultGroupName = groupNameAsSet; } public static void SetValueDefaults(int userId, string userName, int groupId, string groupName) { defaultUserId = (userIdAsSet = userId); defaultUser = (userNameAsSet = userName); defaultGroupId = (groupIdAsSet = groupId); defaultGroupName = (groupNameAsSet = groupName); } internal static void SetActiveDefaults(int userId, string userName, int groupId, string groupName) { defaultUserId = userId; defaultUser = userName; defaultGroupId = groupId; defaultGroupName = groupName; } public static void ResetValueDefaults() { defaultUserId = 0; defaultGroupId = 0; defaultGroupName = "None"; defaultUser = null; } public object Clone() { TarHeader tarHeader = new TarHeader(); tarHeader.Name = Name; tarHeader.Mode = Mode; tarHeader.UserId = UserId; tarHeader.GroupId = GroupId; tarHeader.Size = Size; tarHeader.ModTime = ModTime; tarHeader.TypeFlag = TypeFlag; tarHeader.LinkName = LinkName; tarHeader.Magic = Magic; tarHeader.Version = Version; tarHeader.UserName = UserName; tarHeader.GroupName = GroupName; tarHeader.DevMajor = DevMajor; tarHeader.DevMinor = DevMinor; return tarHeader; } public override int GetHashCode() { return Name.GetHashCode(); } public override bool Equals(object obj) { if (obj is TarHeader) { TarHeader tarHeader = obj as TarHeader; return name == tarHeader.name && mode == tarHeader.mode && UserId == tarHeader.UserId && GroupId == tarHeader.GroupId && Size == tarHeader.Size && ModTime == tarHeader.ModTime && Checksum == tarHeader.Checksum && TypeFlag == tarHeader.TypeFlag && LinkName == tarHeader.LinkName && Magic == tarHeader.Magic && Version == tarHeader.Version && UserName == tarHeader.UserName && GroupName == tarHeader.GroupName && DevMajor == tarHeader.DevMajor && DevMinor == tarHeader.DevMinor; } return false; } [Obsolete] public string GetName() { return name.ToString(); } public static long ParseOctal(byte[] header, int offset, int length) { long num = 0L; bool flag = true; int num2 = offset + length; for (int i = offset; i < num2 && header[i] != 0; i++) { if (header[i] == 32 || header[i] == 48) { if (flag) { continue; } if (header[i] == 32) { break; } } flag = false; num = (num << 3) + (header[i] - 48); } return num; } public static StringBuilder ParseName(byte[] header, int offset, int length) { StringBuilder stringBuilder = new StringBuilder(length); for (int i = offset; i < offset + length && header[i] != 0; i++) { stringBuilder.Append((char)header[i]); } return stringBuilder; } public static int GetNameBytes(StringBuilder name, int nameOffset, byte[] buf, int bufferOffset, int length) { return GetNameBytes(name.ToString(), nameOffset, buf, bufferOffset, length); } public static int GetNameBytes(string name, int nameOffset, byte[] buf, int bufferOffset, int length) { int i; for (i = 0; i < length - 1 && nameOffset + i < name.Length; i++) { buf[bufferOffset + i] = (byte)name[nameOffset + i]; } for (; i < length; i++) { buf[bufferOffset + i] = 0; } return bufferOffset + length; } public static int GetNameBytes(StringBuilder name, byte[] buf, int offset, int length) { return GetNameBytes(name.ToString(), 0, buf, offset, length); } public static int GetNameBytes(string name, byte[] buf, int offset, int length) { return GetNameBytes(name, 0, buf, offset, length); } public static int GetAsciiBytes(string toAdd, int nameOffset, byte[] buffer, int bufferOffset, int length) { for (int i = 0; i < length && nameOffset + i < toAdd.Length; i++) { buffer[bufferOffset + i] = (byte)toAdd[nameOffset + i]; } return bufferOffset + length; } public static int GetOctalBytes(long val, byte[] buf, int offset, int length) { int num = length - 1; buf[offset + num] = 0; num--; if (val > 0) { long num2 = val; while (num >= 0 && num2 > 0) { buf[offset + num] = (byte)(48 + (byte)(num2 & 7)); num2 >>= 3; num--; } } while (num >= 0) { buf[offset + num] = 48; num--; } return offset + length; } public static int GetLongOctalBytes(long val, byte[] buf, int offset, int length) { return GetOctalBytes(val, buf, offset, length); } private static int GetCheckSumOctalBytes(long val, byte[] buf, int offset, int length) { GetOctalBytes(val, buf, offset, length - 1); return offset + length; } private static int ComputeCheckSum(byte[] buf) { int num = 0; for (int i = 0; i < buf.Length; i++) { num += buf[i]; } return num; } private static int MakeCheckSum(byte[] buf) { int num = 0; for (int i = 0; i < 148; i++) { num += buf[i]; } for (int j = 0; j < CHKSUMLEN; j++) { num += 32; } for (int k = 148 + CHKSUMLEN; k < buf.Length; k++) { num += buf[k]; } return num; } private static int GetCTime(DateTime dateTime) { long ticks = dateTime.Ticks; DateTime dateTime2 = dateTime1970; return (int)((ticks - dateTime2.Ticks) / timeConversionFactor); } private static DateTime GetDateTimeFromCTime(long ticks) { DateTime result; try { DateTime dateTime = dateTime1970; result = new DateTime(dateTime.Ticks + ticks * timeConversionFactor); } catch { return dateTime1970; } return result; } public void ParseBuffer(byte[] header) { int num = 0; name = ParseName(header, num, NAMELEN).ToString(); num += NAMELEN; mode = (int)ParseOctal(header, num, MODELEN); num += MODELEN; UserId = (int)ParseOctal(header, num, UIDLEN); num += UIDLEN; GroupId = (int)ParseOctal(header, num, GIDLEN); num += GIDLEN; Size = ParseOctal(header, num, SIZELEN); num += SIZELEN; ModTime = GetDateTimeFromCTime(ParseOctal(header, num, MODTIMELEN)); num += MODTIMELEN; checksum = (int)ParseOctal(header, num, CHKSUMLEN); num += CHKSUMLEN; TypeFlag = header[num++]; LinkName = ParseName(header, num, NAMELEN).ToString(); num += NAMELEN; Magic = ParseName(header, num, MAGICLEN).ToString(); num += MAGICLEN; Version = ParseName(header, num, VERSIONLEN).ToString(); num += VERSIONLEN; UserName = ParseName(header, num, UNAMELEN).ToString(); num += UNAMELEN; GroupName = ParseName(header, num, GNAMELEN).ToString(); num += GNAMELEN; DevMajor = (int)ParseOctal(header, num, DEVLEN); num += DEVLEN; DevMinor = (int)ParseOctal(header, num, DEVLEN); isChecksumValid = Checksum == MakeCheckSum(header); } public void WriteHeader(byte[] outbuf) { int offset = 0; offset = GetNameBytes(Name, outbuf, offset, NAMELEN); offset = GetOctalBytes(mode, outbuf, offset, MODELEN); offset = GetOctalBytes(UserId, outbuf, offset, UIDLEN); offset = GetOctalBytes(GroupId, outbuf, offset, GIDLEN); long val = Size; offset = GetLongOctalBytes(val, outbuf, offset, SIZELEN); offset = GetLongOctalBytes(GetCTime(ModTime), outbuf, offset, MODTIMELEN); int offset2 = offset; for (int i = 0; i < CHKSUMLEN; i++) { outbuf[offset++] = 32; } outbuf[offset++] = TypeFlag; offset = GetNameBytes(LinkName, outbuf, offset, NAMELEN); offset = GetAsciiBytes(Magic, 0, outbuf, offset, MAGICLEN); offset = GetNameBytes(Version, outbuf, offset, VERSIONLEN); offset = GetNameBytes(UserName, outbuf, offset, UNAMELEN); offset = GetNameBytes(GroupName, outbuf, offset, GNAMELEN); if (TypeFlag == 51 || TypeFlag == 52) { offset = GetOctalBytes(DevMajor, outbuf, offset, DEVLEN); offset = GetOctalBytes(DevMinor, outbuf, offset, DEVLEN); } while (offset < outbuf.Length) { outbuf[offset++] = 0; } checksum = ComputeCheckSum(outbuf); GetCheckSumOctalBytes(checksum, outbuf, offset2, CHKSUMLEN); isChecksumValid = true; } } internal class TarBuffer { public const int BlockSize = 512; public const int DefaultBlockFactor = 20; public const int DefaultRecordSize = 10240; private Stream inputStream; private Stream outputStream; private byte[] recordBuffer; private int currentBlockIndex; private int currentRecordIndex; private int recordSize = 10240; private int blockFactor = 20; public int RecordSize => recordSize; public int BlockFactor => blockFactor; protected TarBuffer() { } public static TarBuffer CreateInputTarBuffer(Stream inputStream) { return CreateInputTarBuffer(inputStream, 20); } public static TarBuffer CreateInputTarBuffer(Stream inputStream, int blockFactor) { TarBuffer tarBuffer = new TarBuffer(); tarBuffer.inputStream = inputStream; tarBuffer.outputStream = null; tarBuffer.Initialize(blockFactor); return tarBuffer; } public static TarBuffer CreateOutputTarBuffer(Stream outputStream) { return CreateOutputTarBuffer(outputStream, 20); } public static TarBuffer CreateOutputTarBuffer(Stream outputStream, int blockFactor) { TarBuffer tarBuffer = new TarBuffer(); tarBuffer.inputStream = null; tarBuffer.outputStream = outputStream; tarBuffer.Initialize(blockFactor); return tarBuffer; } private void Initialize(int blockFactor) { this.blockFactor = blockFactor; recordSize = blockFactor * 512; recordBuffer = new byte[RecordSize]; if (inputStream != null) { currentRecordIndex = -1; currentBlockIndex = BlockFactor; } else { currentRecordIndex = 0; currentBlockIndex = 0; } } public int GetBlockFactor() { return blockFactor; } public int GetRecordSize() { return recordSize; } public bool IsEOFBlock(byte[] block) { int i = 0; for (int num = 512; i < num; i++) { if (block[i] != 0) { return false; } } return true; } public void SkipBlock() { if (inputStream == null) { throw new TarException("no input stream defined"); } if (currentBlockIndex < BlockFactor || ReadRecord()) { currentBlockIndex++; } } public byte[] ReadBlock() { if (inputStream == null) { throw new TarException("TarBuffer.ReadBlock - no input stream defined"); } if (currentBlockIndex >= BlockFactor && !ReadRecord()) { return null; } byte[] array = new byte[512]; Array.Copy(recordBuffer, currentBlockIndex * 512, array, 0, 512); currentBlockIndex++; return array; } private bool ReadRecord() { if (inputStream == null) { throw new TarException("no input stream stream defined"); } currentBlockIndex = 0; int num = 0; int num2 = RecordSize; while (num2 > 0) { long num3 = inputStream.Read(recordBuffer, num, num2); if (num3 <= 0) { break; } num += (int)num3; num2 -= (int)num3; } currentRecordIndex++; return true; } public int GetCurrentBlockNum() { return currentBlockIndex; } public int GetCurrentRecordNum() { return currentRecordIndex; } public void WriteBlock(byte[] block) { if (outputStream == null) { throw new TarException("TarBuffer.WriteBlock - no output stream defined"); } if (block.Length != 512) { throw new TarException("TarBuffer.WriteBlock - block to write has length '" + block.Length + "' which is not the block size of '" + 512 + "'"); } if (currentBlockIndex >= BlockFactor) { WriteRecord(); } Array.Copy(block, 0, recordBuffer, currentBlockIndex * 512, 512); currentBlockIndex++; } public void WriteBlock(byte[] buf, int offset) { if (outputStream == null) { throw new TarException("TarBuffer.WriteBlock - no output stream stream defined"); } if (offset + 512 > buf.Length) { throw new TarException("TarBuffer.WriteBlock - record has length '" + buf.Length + "' with offset '" + offset + "' which is less than the record size of '" + recordSize + "'"); } if (currentBlockIndex >= BlockFactor) { WriteRecord(); } Array.Copy(buf, offset, recordBuffer, currentBlockIndex * 512, 512); currentBlockIndex++; } private void WriteRecord() { if (outputStream == null) { throw new TarException("TarBuffer.WriteRecord no output stream defined"); } outputStream.Write(recordBuffer, 0, RecordSize); outputStream.Flush(); currentBlockIndex = 0; currentRecordIndex++; } private void Flush() { if (outputStream == null) { throw new TarException("TarBuffer.Flush no output stream defined"); } if (currentBlockIndex > 0) { WriteRecord(); } outputStream.Flush(); } public void Close() { if (outputStream != null) { Flush(); outputStream.Close(); outputStream = null; } else if (inputStream != null) { inputStream.Close(); inputStream = null; } } } internal class TarInputStream : Stream { public interface IEntryFactory { TarEntry CreateEntry(string name); TarEntry CreateEntryFromFile(string fileName); TarEntry CreateEntry(byte[] headerBuf); } public class EntryFactoryAdapter : IEntryFactory { public TarEntry CreateEntry(string name) { return TarEntry.CreateTarEntry(name); } public TarEntry CreateEntryFromFile(string fileName) { return TarEntry.CreateEntryFromFile(fileName); } public TarEntry CreateEntry(byte[] headerBuf) { return new TarEntry(headerBuf); } } protected bool hasHitEOF; protected long entrySize; protected long entryOffset; protected byte[] readBuf; protected TarBuffer buffer; protected TarEntry currEntry; protected IEntryFactory eFactory; private Stream inputStream; public override bool CanRead => inputStream.CanRead; public override bool CanSeek => false; public override bool CanWrite => false; public override long Length => inputStream.Length; public override long Position { get { return inputStream.Position; } set { throw new NotSupportedException("TarInputStream Seek not supported"); } } public long Available => entrySize - entryOffset; public bool IsMarkSupported => false; public TarInputStream(Stream inputStream) : this(inputStream, 20) { } public TarInputStream(Stream inputStream, int blockFactor) { this.inputStream = inputStream; buffer = TarBuffer.CreateInputTarBuffer(inputStream, blockFactor); readBuf = null; hasHitEOF = false; eFactory = null; } public override void Flush() { inputStream.Flush(); } public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException("TarInputStream Seek not supported"); } public override void SetLength(long val) { throw new NotSupportedException("TarInputStream SetLength not supported"); } public override void Write(byte[] array, int offset, int count) { throw new NotSupportedException("TarInputStream Write not supported"); } public override void WriteByte(byte val) { throw new NotSupportedException("TarInputStream WriteByte not supported"); } public void SetEntryFactory(IEntryFactory factory) { eFactory = factory; } public override void Close() { buffer.Close(); } public int GetRecordSize() { return buffer.GetRecordSize(); } public void Skip(long numToSkip) { byte[] array = new byte[8192]; long num = numToSkip; while (num > 0) { int count = (int)((num <= array.Length) ? num : array.Length); int num2 = Read(array, 0, count); if (num2 == -1) { break; } num -= num2; } } public void Mark(int markLimit) { } public void Reset() { } private void SkipToNextEntry() { long num = entrySize - entryOffset; if (num > 0) { Skip(num); } readBuf = null; } public TarEntry GetNextEntry() { if (hasHitEOF) { return null; } if (currEntry != null) { SkipToNextEntry(); } byte[] array = buffer.ReadBlock(); if (array == null) { hasHitEOF = true; } else if (buffer.IsEOFBlock(array)) { hasHitEOF = true; } if (hasHitEOF) { currEntry = null; } else { try { TarHeader tarHeader = new TarHeader(); tarHeader.ParseBuffer(array); if (!tarHeader.IsChecksumValid) { throw new TarException("Header checksum is invalid"); } entryOffset = 0L; entrySize = tarHeader.Size; StringBuilder stringBuilder = null; if (tarHeader.TypeFlag == 76) { byte[] array2 = new byte[512]; long num = entrySize; stringBuilder = new StringBuilder(); while (num > 0) { int num2 = Read(array2, 0, (int)((num <= array2.Length) ? num : array2.Length)); if (num2 == -1) { throw new InvalidHeaderException("Failed to read long name entry"); } stringBuilder.Append(TarHeader.ParseName(array2, 0, num2).ToString()); num -= num2; } SkipToNextEntry(); array = buffer.ReadBlock(); } else if (tarHeader.TypeFlag == 103) { SkipToNextEntry(); array = buffer.ReadBlock(); } else if (tarHeader.TypeFlag == TarHeader.LF_XHDR) { SkipToNextEntry(); array = buffer.ReadBlock(); } else if (tarHeader.TypeFlag == 86) { SkipToNextEntry(); array = buffer.ReadBlock(); } else if (tarHeader.TypeFlag != 48 && tarHeader.TypeFlag != 0 && tarHeader.TypeFlag != 53) { SkipToNextEntry(); array = buffer.ReadBlock(); } if (eFactory == null) { currEntry = new TarEntry(array); if (stringBuilder != null) { currEntry.Name = stringBuilder.ToString(); } } else { currEntry = eFactory.CreateEntry(array); } entryOffset = 0L; entrySize = currEntry.Size; } catch (InvalidHeaderException ex) { entrySize = 0L; entryOffset = 0L; currEntry = null; throw new InvalidHeaderException("bad header in record " + buffer.GetCurrentBlockNum() + " block " + buffer.GetCurrentBlockNum() + ", " + ex.Message); } } return currEntry; } public override int ReadByte() { byte[] array = new byte[1]; int num = Read(array, 0, 1); if (num <= 0) { return -1; } return array[0]; } public override int Read(byte[] outputBuffer, int offset, int count) { int num = 0; if (entryOffset >= entrySize) { return 0; } long num2 = count; if (num2 + entryOffset > entrySize) { num2 = entrySize - entryOffset; } if (readBuf != null) { int num3 = (int)((num2 <= readBuf.Length) ? num2 : readBuf.Length); Array.Copy(readBuf, 0, outputBuffer, offset, num3); if (num3 >= readBuf.Length) { readBuf = null; } else { int num4 = readBuf.Length - num3; byte[] destinationArray = new byte[num4]; Array.Copy(readBuf, num3, destinationArray, 0, num4); readBuf = destinationArray; } num += num3; num2 -= num3; offset += num3; } while (num2 > 0) { byte[] array = buffer.ReadBlock(); if (array == null) { throw new TarException("unexpected EOF with " + num2 + " bytes unread"); } int num5 = (int)num2; int num6 = array.Length; if (num6 > num5) { Array.Copy(array, 0, outputBuffer, offset, num5); readBuf = new byte[num6 - num5]; Array.Copy(array, num5, readBuf, 0, num6 - num5); } else { num5 = num6; Array.Copy(array, 0, outputBuffer, offset, num6); } num += num5; num2 -= num5; offset += num5; } entryOffset += num; return num; } public void CopyEntryContents(Stream outputStream) { byte[] array = new byte[32768]; while (true) { int num = Read(array, 0, array.Length); if (num <= 0) { break; } outputStream.Write(array, 0, num); } } } internal class TarOutputStream : Stream { protected bool debug; protected long currSize; protected long currBytes; protected byte[] blockBuf; protected int assemLen; protected byte[] assemBuf; protected TarBuffer buffer; protected Stream outputStream; public override bool CanRead => outputStream.CanRead; public override bool CanSeek => outputStream.CanSeek; public override bool CanWrite => outputStream.CanWrite; public override long Length => outputStream.Length; public override long Position { get { return outputStream.Position; } set { outputStream.Position = value; } } public TarOutputStream(Stream outputStream) : this(outputStream, 20) { } public TarOutputStream(Stream outputStream, int blockFactor) { this.outputStream = outputStream; buffer = TarBuffer.CreateOutputTarBuffer(outputStream, blockFactor); debug = false; assemLen = 0; assemBuf = new byte[512]; blockBuf = new byte[512]; } public override long Seek(long offset, SeekOrigin origin) { return outputStream.Seek(offset, origin); } public override void SetLength(long val) { outputStream.SetLength(val); } public override int ReadByte() { return outputStream.ReadByte(); } public override int Read(byte[] b, int off, int len) { return outputStream.Read(b, off, len); } public override void Flush() { outputStream.Flush(); } public void Finish() { WriteEOFRecord(); } public override void Close() { Finish(); buffer.Close(); } public int GetRecordSize() { return buffer.GetRecordSize(); } public void PutNextEntry(TarEntry entry) { if (entry.TarHeader.Name.Length >= TarHeader.NAMELEN) { TarHeader tarHeader = new TarHeader(); tarHeader.TypeFlag = 76; tarHeader.Name += "././@LongLink"; tarHeader.UserId = 0; tarHeader.GroupId = 0; tarHeader.GroupName = ""; tarHeader.UserName = ""; tarHeader.LinkName = ""; tarHeader.Size = entry.TarHeader.Name.Length; tarHeader.WriteHeader(blockBuf); buffer.WriteBlock(blockBuf); int num = 0; while (num < entry.TarHeader.Name.Length) { Array.Clear(blockBuf, 0, blockBuf.Length); TarHeader.GetAsciiBytes(entry.TarHeader.Name, num, blockBuf, 0, 512); num += 512; buffer.WriteBlock(blockBuf); } } entry.WriteEntryHeader(blockBuf); buffer.WriteBlock(blockBuf); currBytes = 0L; currSize = ((!entry.IsDirectory) ? entry.Size : 0); } public void CloseEntry() { if (assemLen > 0) { for (int i = assemLen; i < assemBuf.Length; i++) { assemBuf[i] = 0; } buffer.WriteBlock(assemBuf); currBytes += assemLen; assemLen = 0; } if (currBytes < currSize) { throw new TarException("entry closed at '" + currBytes + "' before the '" + currSize + "' bytes specified in the header were written"); } } public override void WriteByte(byte b) { Write(new byte[1] { b }, 0, 1); } public override void Write(byte[] wBuf, int wOffset, int numToWrite) { if (wBuf == null) { throw new ArgumentNullException("TarOutputStream.Write buffer null"); } if (currBytes + numToWrite > currSize) { throw new ArgumentOutOfRangeException("request to write '" + numToWrite + "' bytes exceeds size in header of '" + currSize + "' bytes"); } if (assemLen > 0) { if (assemLen + numToWrite >= blockBuf.Length) { int num = blockBuf.Length - assemLen; Array.Copy(assemBuf, 0, blockBuf, 0, assemLen); Array.Copy(wBuf, wOffset, blockBuf, assemLen, num); buffer.WriteBlock(blockBuf); currBytes += blockBuf.Length; wOffset += num; numToWrite -= num; assemLen = 0; } else { Array.Copy(wBuf, wOffset, assemBuf, assemLen, numToWrite); wOffset += numToWrite; assemLen += numToWrite; numToWrite -= numToWrite; } } while (numToWrite > 0) { if (numToWrite < blockBuf.Length) { Array.Copy(wBuf, wOffset, assemBuf, assemLen, numToWrite); assemLen += numToWrite; break; } buffer.WriteBlock(wBuf, wOffset); int num2 = blockBuf.Length; currBytes += num2; numToWrite -= num2; wOffset += num2; } } private void WriteEOFRecord() { Array.Clear(blockBuf, 0, blockBuf.Length); buffer.WriteBlock(blockBuf); } } internal class TarException : SharpZipBaseException { public TarException() { } public TarException(string message) : base(message) { } } internal class TarArchive { private bool keepOldFiles; private bool asciiTranslate; private int userId; private string userName; private int groupId; private string groupName; private string rootPath; private string pathPrefix; private int recordSize; private byte[] recordBuf; private TarInputStream tarIn; private TarOutputStream tarOut; private bool applyUserInfoOverrides; public string PathPrefix { get { return pathPrefix; } set { pathPrefix = value; } } public string RootPath { get { return rootPath; } set { rootPath = value; } } public bool ApplyUserInfoOverrides { get { return applyUserInfoOverrides; } set { applyUserInfoOverrides = value; } } public int UserId => userId; public string UserName => userName; public int GroupId => groupId; public string GroupName => groupName; public int RecordSize { get { if (tarIn != null) { return tarIn.GetRecordSize(); } if (tarOut != null) { return tarOut.GetRecordSize(); } return 10240; } } public event ProgressMessageHandler ProgressMessageEvent; protected TarArchive() { } protected virtual void OnProgressMessageEvent(TarEntry entry, string message) { if (this.ProgressMessageEvent != null) { this.ProgressMessageEvent(this, entry, message); } } public static TarArchive CreateInputTarArchive(Stream inputStream) { return CreateInputTarArchive(inputStream, 20); } public static TarArchive CreateInputTarArchive(Stream inputStream, int blockFactor) { TarArchive tarArchive = new TarArchive(); tarArchive.tarIn = new TarInputStream(inputStream, blockFactor); tarArchive.Initialize(blockFactor * 512); return tarArchive; } public static TarArchive CreateOutputTarArchive(Stream outputStream) { return CreateOutputTarArchive(outputStream, 20); } public static TarArchive CreateOutputTarArchive(Stream outputStream, int blockFactor) { TarArchive tarArchive = new TarArchive(); tarArchive.tarOut = new TarOutputStream(outputStream, blockFactor); tarArchive.Initialize(blockFactor * 512); return tarArchive; } private void Initialize(int recordSize) { this.recordSize = recordSize; rootPath = null; pathPrefix = null; userId = 0; userName = string.Empty; groupId = 0; groupName = string.Empty; keepOldFiles = false; recordBuf = new byte[RecordSize]; } public void SetKeepOldFiles(bool keepOldFiles) { this.keepOldFiles = keepOldFiles; } public void SetAsciiTranslation(bool asciiTranslate) { this.asciiTranslate = asciiTranslate; } public void SetUserInfo(int userId, string userName, int groupId, string groupName) { this.userId = userId; this.userName = userName; this.groupId = groupId; this.groupName = groupName; applyUserInfoOverrides = true; } public void CloseArchive() { if (tarIn != null) { tarIn.Close(); } else if (tarOut != null) { tarOut.Flush(); tarOut.Close(); } } public void ListContents() { while (true) { TarEntry nextEntry = tarIn.GetNextEntry(); if (nextEntry == null) { break; } OnProgressMessageEvent(nextEntry, null); } } public void ExtractContents(string destDir) { while (true) { TarEntry nextEntry = tarIn.GetNextEntry(); if (nextEntry == null) { break; } ExtractEntry(destDir, nextEntry); } } private void EnsureDirectoryExists(string directoryName) { if (!Directory.Exists(directoryName)) { try { Directory.CreateDirectory(directoryName); } catch (Exception ex) { throw new TarException("Exception creating directory '" + directoryName + "', " + ex.Message); } } } private bool IsBinary(string filename) { using (FileStream fileStream = File.OpenRead(filename)) { try { int num = Math.Min(4096, (int)fileStream.Length); byte[] array = new byte[num]; int num2 = fileStream.Read(array, 0, num); for (int i = 0; i < num2; i++) { byte b = array[i]; if (b < 8 || (b > 13 && b < 32) || b == byte.MaxValue) { return true; } } } finally { } } return false; } private void ExtractEntry(string destDir, TarEntry entry) { OnProgressMessageEvent(entry, null); string text = entry.Name; if (Path.IsPathRooted(text)) { text = text.Substring(Path.GetPathRoot(text).Length); } text = text.Replace('/', Path.DirectorySeparatorChar); string text2 = Path.Combine(destDir, text); if (entry.IsDirectory) { EnsureDirectoryExists(text2); return; } string directoryName = Path.GetDirectoryName(text2); EnsureDirectoryExists(directoryName); bool flag = true; FileInfo fileInfo = new FileInfo(text2); if (fileInfo.Exists) { if (keepOldFiles) { OnProgressMessageEvent(entry, "Destination file already exists"); flag = false; } else if ((fileInfo.Attributes & FileAttributes.ReadOnly) != 0) { OnProgressMessageEvent(entry, "Destination file already exists, and is read-only"); flag = false; } } if (!flag) { return; } bool flag2 = false; Stream stream = File.Create(text2); if (asciiTranslate) { flag2 = !IsBinary(text2); } StreamWriter streamWriter = null; if (flag2) { streamWriter = new StreamWriter(stream); } byte[] array = new byte[32768]; while (true) { int num = tarIn.Read(array, 0, array.Length); if (num <= 0) { break; } if (flag2) { int num2 = 0; for (int i = 0; i < num; i++) { if (array[i] == 10) { string @string = Encoding.ASCII.GetString(array, num2, i - num2); streamWriter.WriteLine(@string); num2 = i + 1; } } } else { stream.Write(array, 0, num); } } if (flag2) { streamWriter.Close(); } else { stream.Close(); } } public void WriteEntry(TarEntry sourceEntry, bool recurse) { try { if (recurse) { TarHeader.SetValueDefaults(sourceEntry.UserId, sourceEntry.UserName, sourceEntry.GroupId, sourceEntry.GroupName); } InternalWriteEntry(sourceEntry, recurse); } finally { if (recurse) { TarHeader.RestoreSetValues(); } } } private void InternalWriteEntry(TarEntry sourceEntry, bool recurse) { bool flag = false; string text = null; string text2 = sourceEntry.File; TarEntry tarEntry = (TarEntry)sourceEntry.Clone(); if (applyUserInfoOverrides) { tarEntry.GroupId = groupId; tarEntry.GroupName = groupName; tarEntry.UserId = userId; tarEntry.UserName = userName; } OnProgressMessageEvent(tarEntry, null); if (asciiTranslate && !tarEntry.IsDirectory && !IsBinary(text2)) { text = Path.GetTempFileName(); StreamReader streamReader = File.OpenText(text2); Stream stream = File.Create(text); while (true) { string text3 = streamReader.ReadLine(); if (text3 == null) { break; } byte[] bytes = Encoding.ASCII.GetBytes(text3); stream.Write(bytes, 0, bytes.Length); stream.WriteByte(10); } streamReader.Close(); stream.Flush(); stream.Close(); tarEntry.Size = new FileInfo(text).Length; text2 = text; } string text4 = null; if (rootPath != null && tarEntry.Name.StartsWith(rootPath)) { text4 = tarEntry.Name.Substring(rootPath.Length + 1); } if (pathPrefix != null) { text4 = ((text4 != null) ? (pathPrefix + "/" + text4) : (pathPrefix + "/" + tarEntry.Name)); } if (text4 != null) { tarEntry.Name = text4; } tarOut.PutNextEntry(tarEntry); if (tarEntry.IsDirectory) { if (recurse) { TarEntry[] directoryEntries = tarEntry.GetDirectoryEntries(); for (int i = 0; i < directoryEntries.Length; i++) { InternalWriteEntry(directoryEntries[i], recurse); } } return; } Stream stream2 = File.OpenRead(text2); int num = 0; byte[] array = new byte[32768]; while (true) { int num2 = stream2.Read(array, 0, array.Length); if (num2 <= 0) { break; } tarOut.Write(array, 0, num2); num += num2; } stream2.Close(); if (text != null && text.Length > 0) { File.Delete(text); } tarOut.CloseEntry(); } } internal class TarEntry : ICloneable { private string file; private TarHeader header; public TarHeader TarHeader => header; public string Name { get { return header.Name; } set { header.Name = value; } } public int UserId { get { return header.UserId; } set { header.UserId = value; } } public int GroupId { get { return header.GroupId; } set { header.GroupId = value; } } public string UserName { get { return header.UserName; } set { header.UserName = value; } } public string GroupName { get { return header.GroupName; } set { header.GroupName = value; } } public DateTime ModTime { get { return header.ModTime; } set { header.ModTime = value; } } public string File => file; public long Size { get { return header.Size; } set { header.Size = value; } } public bool IsDirectory { get { if (file != null) { return Directory.Exists(file); } if (header != null && (header.TypeFlag == 53 || Name.EndsWith("/"))) { return true; } return false; } } private TarEntry() { } public TarEntry(byte[] headerBuf) { Initialize(); header.ParseBuffer(headerBuf); } public TarEntry(TarHeader header) { file = null; this.header = header; } public object Clone() { TarEntry tarEntry = new TarEntry(); tarEntry.file = file; tarEntry.header = (TarHeader)header.Clone(); tarEntry.Name = Name; return tarEntry; } public static TarEntry CreateTarEntry(string name) { TarEntry tarEntry = new TarEntry(); tarEntry.Initialize(); tarEntry.NameTarHeader(tarEntry.header, name); return tarEntry; } public static TarEntry CreateEntryFromFile(string fileName) { TarEntry tarEntry = new TarEntry(); tarEntry.Initialize(); tarEntry.GetFileTarHeader(tarEntry.header, fileName); return tarEntry; } private void Initialize() { file = null; header = new TarHeader(); } public override bool Equals(object it) { if (!(it is TarEntry)) { return false; } return Name.Equals(((TarEntry)it).Name); } public override int GetHashCode() { return Name.GetHashCode(); } public bool IsDescendent(TarEntry desc) { return desc.Name.StartsWith(Name); } public void SetIds(int userId, int groupId) { UserId = userId; GroupId = groupId; } public void SetNames(string userName, string groupName) { UserName = userName; GroupName = groupName; } public void AdjustEntryName(byte[] outbuf, string newName) { int offset = 0; TarHeader.GetNameBytes(newName, outbuf, offset, TarHeader.NAMELEN); } public void GetFileTarHeader(TarHeader hdr, string file) { this.file = file; string text = file; if (text.IndexOf(Environment.CurrentDirectory) == 0) { text = text.Substring(Environment.CurrentDirectory.Length); } text = text.Replace(Path.DirectorySeparatorChar, '/'); while (text.StartsWith("/")) { text = text.Substring(1); } hdr.LinkName = string.Empty; hdr.Name = text; if (Directory.Exists(file)) { hdr.Mode = 1003; hdr.TypeFlag = 53; if (hdr.Name.Length == 0 || hdr.Name[hdr.Name.Length - 1] != '/') { hdr.Name += "/"; } hdr.Size = 0L; } else { hdr.Mode = 33216; hdr.TypeFlag = 48; hdr.Size = new FileInfo(file.Replace('/', Path.DirectorySeparatorChar)).Length; } hdr.ModTime = System.IO.File.GetLastWriteTime(file.Replace('/', Path.DirectorySeparatorChar)).ToUniversalTime(); hdr.DevMajor = 0; hdr.DevMinor = 0; } public TarEntry[] GetDirectoryEntries() { if (file == null || !Directory.Exists(file)) { return new TarEntry[0]; } string[] fileSystemEntries = Directory.GetFileSystemEntries(file); TarEntry[] array = new TarEntry[fileSystemEntries.Length]; for (int i = 0; i < fileSystemEntries.Length; i++) { array[i] = CreateEntryFromFile(fileSystemEntries[i]); } return array; } public void WriteEntryHeader(byte[] outbuf) { header.WriteHeader(outbuf); } public void NameTarHeader(TarHeader hdr, string name) { bool flag = name.EndsWith("/"); hdr.Name = name; hdr.Mode = ((!flag) ? 33216 : 1003); hdr.UserId = 0; hdr.GroupId = 0; hdr.Size = 0L; hdr.ModTime = DateTime.UtcNow; hdr.TypeFlag = (byte)((!flag) ? 48 : 53); hdr.LinkName = string.Empty; hdr.UserName = string.Empty; hdr.GroupName = string.Empty; hdr.DevMajor = 0; hdr.DevMinor = 0; } } } namespace ICSharpCode.SharpZipLib.Core { internal class ScanEventArgs : EventArgs { private string name; private bool continueRunning; public string Name => name; public bool ContinueRunning { get { return continueRunning; } set { continueRunning = value; } } public ScanEventArgs(string name) { this.name = name; ContinueRunning = true; } } internal class DirectoryEventArgs : ScanEventArgs { private bool hasMatchingFiles; public bool HasMatchingFiles => hasMatchingFiles; public DirectoryEventArgs(string name, bool hasMatchingFiles) : base(name) { this.hasMatchingFiles = hasMatchingFiles; } } internal class ScanFailureEventArgs { private string name; private Exception exception; private bool continueRunning; public string Name => name; public Exception Exception => exception; public bool ContinueRunning { get { return continueRunning; } set { continueRunning = value; } } public ScanFailureEventArgs(string name, Exception e) { this.name = name; exception = e; continueRunning = true; } } internal class FileSystemScanner { public ProcessDirectoryDelegate ProcessDirectory; public ProcessFileDelegate ProcessFile; public DirectoryFailureDelegate DirectoryFailure; public FileFailureDelegate FileFailure; private IScanFilter fileFilter; private IScanFilter directoryFilter; private bool alive; public FileSystemScanner(string filter) { fileFilter = new PathFilter(filter); } public FileSystemScanner(string fileFilter, string directoryFilter) { this.fileFilter = new PathFilter(fileFilter); this.directoryFilter = new PathFilter(directoryFilter); } public FileSystemScanner(IScanFilter fileFilter) { this.fileFilter = fileFilter; } public FileSystemScanner(IScanFilter fileFilter, IScanFilter directoryFilter) { this.fileFilter = fileFilter; this.directoryFilter = directoryFilter; } public void OnDirectoryFailure(string directory, Exception e) { if (DirectoryFailure == null) { alive = false; return; } ScanFailureEventArgs scanFailureEventArgs = new ScanFailureEventArgs(directory, e); DirectoryFailure(this, scanFailureEventArgs); alive = scanFailureEventArgs.ContinueRunning; } public void OnFileFailure(string file, Exception e) { if (FileFailure == null) { alive = false; return; } ScanFailureEventArgs scanFailureEventArgs = new ScanFailureEventArgs(file, e); FileFailure(this, scanFailureEventArgs); alive = scanFailureEventArgs.ContinueRunning; } public void OnProcessFile(string file) { if (ProcessFile != null) { ScanEventArgs scanEventArgs = new ScanEventArgs(file); ProcessFile(this, scanEventArgs); alive = scanEventArgs.ContinueRunning; } } public void OnProcessDirectory(string directory, bool hasMatchingFiles) { if (ProcessDirectory != null) { DirectoryEventArgs directoryEventArgs = new DirectoryEventArgs(directory, hasMatchingFiles); ProcessDirectory(this, directoryEventArgs); alive = directoryEventArgs.ContinueRunning; } } public void Scan(string directory, bool recurse) { alive = true; ScanDir(directory, recurse); } private void ScanDir(string directory, bool recurse) { try { string[] files = Directory.GetFiles(directory); bool flag = false; for (int i = 0; i < files.Length; i++) { if (!fileFilter.IsMatch(files[i])) { files[i] = null; } else { flag = true; } } OnProcessDirectory(directory, flag); if (alive && flag) { string[] array = files; int num = array.Length; for (int j = 0; j < num; j++) { string text = array[j]; try { if (text != null) { OnProcessFile(text); if (!alive) { break; } } } catch (Exception e) { OnFileFailure(text, e); } } } } catch (Exception e2) { OnDirectoryFailure(directory, e2); } if (!alive || !recurse) { return; } try { string[] directories = Directory.GetDirectories(directory); string[] array2 = directories; int num2 = array2.Length; for (int k = 0; k < num2; k++) { string text2 = array2[k]; if (directoryFilter == null || directoryFilter.IsMatch(text2)) { ScanDir(text2, recurse: true); if (!alive) { break; } } } } catch (Exception e3) { OnDirectoryFailure(directory, e3); } } } internal interface IScanFilter { bool IsMatch(string name); } internal class PathFilter : IScanFilter { private NameFilter nameFilter; public PathFilter(string filter) { nameFilter = new NameFilter(filter); } public virtual bool IsMatch(string name) { return nameFilter.IsMatch(Path.GetFullPath(name)); } } internal class NameAndSizeFilter : PathFilter { private long minSize; private long maxSize = long.MaxValue; public long MinSize { get { return minSize; } set { minSize = value; } } public long MaxSize { get { return maxSize; } set { maxSize = value; } } public NameAndSizeFilter(string filter, long minSize, long maxSize) : base(filter) { this.minSize = minSize; this.maxSize = maxSize; } public override bool IsMatch(string fileName) { FileInfo fileInfo = new FileInfo(fileName); long length = fileInfo.Length; return base.IsMatch(fileName) && MinSize <= length && MaxSize >= length; } } internal interface INameTransform { string TransformFile(string name); string TransformDirectory(string name); } internal class NameFilter { private string filter; private ArrayList inclusions; private ArrayList exclusions; public NameFilter(string filter) { this.filter = filter; inclusions = new ArrayList(); exclusions = new ArrayList(); Compile(); } public static bool IsValidExpression(string e) { bool result = true; try { Regex regex = new Regex(e, RegexOptions.IgnoreCase | RegexOptions.Singleline); } catch { result = false; } return result; } public static bool IsValidFilterExpression(string toTest) { bool result = true; try { string[] array = toTest.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { if (array[i] != null && array[i].Length > 0) { string pattern = ((array[i][0] == '+') ? array[i].Substring(1, array[i].Length - 1) : ((array[i][0] != '-') ? array[i] : array[i].Substring(1, array[i].Length - 1))); Regex regex = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Singleline); } } } catch (Exception) { result = false; } return result; } public override string ToString() { return filter; } public bool IsIncluded(string testValue) { bool result = false; if (inclusions.Count == 0) { result = true; } else { foreach (Regex inclusion in inclusions) { if (inclusion.IsMatch(testValue)) { result = true; break; } } } return result; } public bool IsExcluded(string testValue) { bool result = false; foreach (Regex exclusion in exclusions) { if (exclusion.IsMatch(testValue)) { result = true; break; } } return result; } public bool IsMatch(string testValue) { return IsIncluded(testValue) && !IsExcluded(testValue); } private void Compile() { if (filter == null) { return; } string[] array = filter.Split(new char[1] { ';' }); for (int i = 0; i < array.Length; i++) { if (array[i] != null && array[i].Length > 0) { bool flag = array[i][0] != '-'; string pattern = ((array[i][0] == '+') ? array[i].Substring(1, array[i].Length - 1) : ((array[i][0] != '-') ? array[i] : array[i].Substring(1, array[i].Length - 1))); if (flag) { inclusions.Add(new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)); } else { exclusions.Add(new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.Singleline)); } } } } } } namespace ICSharpCode.SharpZipLib.GZip { internal class GZipInputStream : InflaterInputStream { protected Crc32 crc = new Crc32(); protected bool eos; private bool readGZIPHeader; public GZipInputStream(Stream baseInputStream) : this(baseInputStream, 4096) { } public GZipInputStream(Stream baseInputStream, int size) : base(baseInputStream, new Inflater(noHeader: true), size) { } public override int Read(byte[] buf, int offset, int len) { if (!readGZIPHeader) { ReadHeader(); } if (eos) { return 0; } int num = base.Read(buf, offset, len); if (num > 0) { crc.Update(buf, offset, num); } if (inf.IsFinished) { ReadFooter(); } return num; } private void ReadHeader() { Crc32 crc = new Crc32(); int num = baseInputStream.ReadByte(); if (num < 0) { eos = true; return; } crc.Update(num); if (num != GZipConstants.GZIP_MAGIC >> 8) { throw new GZipException("Error baseInputStream GZIP header, first byte doesn't match"); } num = baseInputStream.ReadByte(); if (num != (GZipConstants.GZIP_MAGIC & 0xFF)) { throw new GZipException("Error baseInputStream GZIP header, second byte doesn't match"); } crc.Update(num); int num2 = baseInputStream.ReadByte(); if (num2 != 8) { throw new GZipException("Error baseInputStream GZIP header, data not baseInputStream deflate format"); } crc.Update(num2); int num3 = baseInputStream.ReadByte(); if (num3 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } crc.Update(num3); if (((uint)num3 & 0xD0u) != 0) { throw new GZipException("Reserved flag bits baseInputStream GZIP header != 0"); } for (int i = 0; i < 6; i++) { int num4 = baseInputStream.ReadByte(); if (num4 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } crc.Update(num4); } if (((uint)num3 & 4u) != 0) { for (int j = 0; j < 2; j++) { int num5 = baseInputStream.ReadByte(); if (num5 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } crc.Update(num5); } if (baseInputStream.ReadByte() < 0 || baseInputStream.ReadByte() < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } int num6 = baseInputStream.ReadByte(); int num7 = baseInputStream.ReadByte(); if (num6 < 0 || num7 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } crc.Update(num6); crc.Update(num7); int num8 = (num6 << 8) | num7; for (int k = 0; k < num8; k++) { int num9 = baseInputStream.ReadByte(); if (num9 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } crc.Update(num9); } } if (((uint)num3 & 8u) != 0) { int num10; while ((num10 = baseInputStream.ReadByte()) > 0) { crc.Update(num10); } if (num10 < 0) { throw new GZipException("Early EOF baseInputStream GZIP file name"); } crc.Update(num10); } if (((uint)num3 & 0x10u) != 0) { int num11; while ((num11 = baseInputStream.ReadByte()) > 0) { crc.Update(num11); } if (num11 < 0) { throw new GZipException("Early EOF baseInputStream GZIP comment"); } crc.Update(num11); } if (((uint)num3 & 2u) != 0) { int num12 = baseInputStream.ReadByte(); if (num12 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } int num13 = baseInputStream.ReadByte(); if (num13 < 0) { throw new GZipException("Early EOF baseInputStream GZIP header"); } num12 = (num12 << 8) | num13; if (num12 != ((int)crc.Value & 0xFFFF)) { throw new GZipException("Header CRC value mismatch"); } } readGZIPHeader = true; } private void ReadFooter() { byte[] array = new byte[8]; int num = inf.RemainingInput; if (num > 8) { num = 8; } Array.Copy(inputBuffer.RawData, inputBuffer.RawLength - inf.RemainingInput, array, 0, num); int num2 = 8 - num; while (num2 > 0) { int num3 = baseInputStream.Read(array, 8 - num2, num2); if (num3 <= 0) { throw new GZipException("Early EOF baseInputStream GZIP footer"); } num2 -= num3; } int num4 = (array[0] & 0xFF) | ((array[1] & 0xFF) << 8) | ((array[2] & 0xFF) << 16) | (array[3] << 24); if (num4 != (int)crc.Value) { throw new GZipException("GZIP crc sum mismatch, theirs \"" + num4 + "\" and ours \"" + (int)crc.Value); } int num5 = (array[4] & 0xFF) | ((array[5] & 0xFF) << 8) | ((array[6] & 0xFF) << 16) | (array[7] << 24); if (num5 != inf.TotalOut) { throw new GZipException("Number of bytes mismatch in footer"); } eos = true; } } internal class GZipConstants { public const int FTEXT = 1; public const int FHCRC = 2; public const int FEXTRA = 4; public const int FNAME = 8; public const int FCOMMENT = 16; public static readonly int GZIP_MAGIC = 8075; private GZipConstants() { } } internal class GZipOutputStream : DeflaterOutputStream { protected Crc32 crc = new Crc32(); public GZipOutputStream(Stream baseOutputStream) : this(baseOutputStream, 4096) { } public GZipOutputStream(Stream baseOutputStream, int size) : base(baseOutputStream, new Deflater(Deflater.DEFAULT_COMPRESSION, noZlibHeaderOrFooter: true), size) { WriteHeader(); } private void WriteHeader() { int num = (int)(DateTime.Now.Ticks / 10000); byte[] array = new byte[10] { (byte)(GZipConstants.GZIP_MAGIC >> 8), (byte)GZipConstants.GZIP_MAGIC, (byte)Deflater.DEFLATED, 0, (byte)num, (byte)(num >> 8), (byte)(num >> 16), (byte)(num >> 24), 0, 255 }; baseOutputStream.Write(array, 0, array.Length); } public override void Write(byte[] buf, int off, int len) { crc.Update(buf, off, len); base.Write(buf, off, len); } public override void Close() { Finish(); if (base.IsStreamOwner) { baseOutputStream.Close(); } } public void SetLevel(int level) { if (level < Deflater.BEST_SPEED) { throw new ArgumentOutOfRangeException("level"); } def.SetLevel(level); } public int GetLevel() { return def.GetLevel(); } public override void Finish() { base.Finish(); int totalIn = def.TotalIn; int num = (int)(crc.Value & 0xFFFFFFFFL); byte[] array = new byte[8] { (byte)num, (byte)(num >> 8), (byte)(num >> 16), (byte)(num >> 24), (byte)totalIn, (byte)(totalIn >> 8), (byte)(totalIn >> 16), (byte)(totalIn >> 24) }; baseOutputStream.Write(array, 0, array.Length); } } internal class GZipException : SharpZipBaseException { public GZipException() { } public GZipException(string message) : base(message) { } } } namespace ICSharpCode.SharpZipLib.Encryption { internal abstract class PkzipClassic : SymmetricAlgorithm { public static byte[] GenerateKeys(byte[] seed) { if (seed == null) { throw new ArgumentNullException("seed"); } if (seed.Length == 0) { throw new ArgumentException("seed"); } uint[] array = new uint[3] { 305419896u, 591751049u, 878082192u }; for (int i = 0; i < seed.Length; i++) { array[0] = Crc32.ComputeCrc32(array[0], seed[i]); array[1] = array[1] + (byte)array[0]; array[1] = array[1] * 134775813 + 1; array[2] = Crc32.ComputeCrc32(array[2], (byte)(array[1] >> 24)); } return new byte[12] { (byte)(array[0] & 0xFFu), (byte)((array[0] >> 8) & 0xFFu), (byte)((array[0] >> 16) & 0xFFu), (byte)((array[0] >> 24) & 0xFFu), (byte)(array[1] & 0xFFu), (byte)((array[1] >> 8) & 0xFFu), (byte)((array[1] >> 16) & 0xFFu), (byte)((array[1] >> 24) & 0xFFu), (byte)(array[2] & 0xFFu), (byte)((array[2] >> 8) & 0xFFu), (byte)((array[2] >> 16) & 0xFFu), (byte)((array[2] >> 24) & 0xFFu) }; } } internal class PkzipClassicCryptoBase { private uint[] keys; protected byte TransformByte() { uint num = (keys[2] & 0xFFFFu) | 2u; return (byte)(num * (num ^ 1) >> 8); } protected void SetKeys(byte[] keyData) { if (keyData == null) { throw new ArgumentNullException("keyData"); } if (keyData.Length != 12) { throw new InvalidOperationException("Keys not valid"); } keys = new uint[3]; keys[0] = (uint)((keyData[3] << 24) | (keyData[2] << 16) | (keyData[1] << 8) | keyData[0]); keys[1] = (uint)((keyData[7] << 24) | (keyData[6] << 16) | (keyData[5] << 8) | keyData[4]); keys[2] = (uint)((keyData[11] << 24) | (keyData[10] << 16) | (keyData[9] << 8) | keyData[8]); } protected void UpdateKeys(byte ch) { keys[0] = Crc32.ComputeCrc32(keys[0], ch); keys[1] = keys[1] + (byte)keys[0]; keys[1] = keys[1] * 134775813 + 1; keys[2] = Crc32.ComputeCrc32(keys[2], (byte)(keys[1] >> 24)); } protected void Reset() { keys[0] = 0u; keys[1] = 0u; keys[2] = 0u; } } internal class PkzipClassicEncryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform, IDisposable { public bool CanReuseTransform => true; public int InputBlockSize => 1; public int OutputBlockSize => 1; public bool CanTransformMultipleBlocks => true; internal PkzipClassicEncryptCryptoTransform(byte[] keyBlock) { SetKeys(keyBlock); } public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { byte[] array = new byte[inputCount]; TransformBlock(inputBuffer, inputOffset, inputCount, array, 0); return array; } public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { for (int i = inputOffset; i < inputOffset + inputCount; i++) { byte ch = inputBuffer[i]; outputBuffer[outputOffset++] = (byte)(inputBuffer[i] ^ TransformByte()); UpdateKeys(ch); } return inputCount; } public void Dispose() { Reset(); } } internal class PkzipClassicDecryptCryptoTransform : PkzipClassicCryptoBase, ICryptoTransform, IDisposable { public bool CanReuseTransform => true; public int InputBlockSize => 1; public int OutputBlockSize => 1; public bool CanTransformMultipleBlocks => true; internal PkzipClassicDecryptCryptoTransform(byte[] keyBlock) { SetKeys(keyBlock); } public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { byte[] array = new byte[inputCount]; TransformBlock(inputBuffer, inputOffset, inputCount, array, 0); return array; } public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { for (int i = inputOffset; i < inputOffset + inputCount; i++) { byte b = (byte)(inputBuffer[i] ^ TransformByte()); outputBuffer[outputOffset++] = b; UpdateKeys(b); } return inputCount; } public void Dispose() { Reset(); } } internal sealed class PkzipClassicManaged : PkzipClassic { private byte[] key; public override int BlockSize { get { return 8; } set { if (value != 8) { throw new CryptographicException(); } } } public override KeySizes[] LegalKeySizes => new KeySizes[1] { new KeySizes(96, 96, 0) }; public override KeySizes[] LegalBlockSizes => new KeySizes[1] { new KeySizes(8, 8, 0) }; public override byte[] Key { get { return key; } set { key = value; } } public override void GenerateIV() { } public override void GenerateKey() { key = new byte[12]; Random random = new Random(); random.NextBytes(key); } public override ICryptoTransform CreateEncryptor(byte[] rgbKey, byte[] rgbIV) { return new PkzipClassicEncryptCryptoTransform(rgbKey); } public override ICryptoTransform CreateDecryptor(byte[] rgbKey, byte[] rgbIV) { return new PkzipClassicDecryptCryptoTransform(rgbKey); } } } namespace ICSharpCode.SharpZipLib { internal class SharpZipBaseException : ApplicationException { public SharpZipBaseException() { } public SharpZipBaseException(string msg) : base(msg) { } public SharpZipBaseException(string message, Exception innerException) : base(message, innerException) { } } } namespace ICSharpCode.SharpZipLib.Tar { internal delegate void ProgressMessageHandler(TarArchive archive, TarEntry entry, string message); } namespace ICSharpCode.SharpZipLib.Core { internal delegate void ProcessDirectoryDelegate(object Sender, DirectoryEventArgs e); internal delegate void ProcessFileDelegate(object sender, ScanEventArgs e); internal delegate void DirectoryFailureDelegate(object sender, ScanFailureEventArgs e); internal delegate void FileFailureDelegate(object sender, ScanFailureEventArgs e); }