using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using System.Text.RegularExpressions; namespace Cryville.Common.Pdt { /// /// Interpreter for Property Definition Tree (PDT) file format. /// /// The object type represented by the PDT. public partial class PdtInterpreter { /// /// The character category map. /// /// /// /// 0x0001White Space /// 0x0010Identifier /// 0x0020Identifier Begin /// 0x0040Digit /// 0x0080Operator /// 0x0100String /// 0x0200Opening Bracket /// 0x0400Closing Bracket /// 0x0800End of Expression /// 0x1000End of Key /// /// readonly static int[] cm = new int[] { // 0 1 2 3 4 5 6 7 8 9 A B C D E F 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0001, 0x0000, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0080, 0x0100, 0x0000, 0x0030, 0x0080, 0x0080, 0x0000, 0x0200, 0x0400, 0x0080, 0x0080, 0x0080, 0x0080, 0x0040, 0x0080, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x0050, 0x1000, 0x1800, 0x0080, 0x0080, 0x0080, 0x0030, 0x0080, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0000, 0x0000, 0x0000, 0x0000, 0x0030, 0x0000, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x0030, 0x1000, 0x0080, 0x1000, 0x0000, 0x0000, }; /// /// Interprets a source string to an object of type . /// /// The source string. /// The interpreted object. public static T Interpret(string src) { return Interpret(src, BinderAttribute.CreateBinderOfType(typeof(T))); } /// /// Interprets a source string to an object of type with a binder. /// /// The source string. /// The binder. /// The interpreted object. public static T Interpret(string src, Binder binder) { return new PdtInterpreter(src, binder).Interpret(); } readonly string _src; readonly Binder _binder; protected int Position { get; private set; } #pragma warning disable IDE1006 protected char cc { get { return _src[Position]; } } protected int ct { get { return cm[cc]; } } protected string tokenb(int flag) { // Token Whitelist int sp = Position; while ((ct & flag) == 0) Position++; return _src.Substring(sp, Position - sp); } protected string tokenw(int flag) { // Token Whitelist int sp = Position; while ((ct & flag) != 0) Position++; return _src.Substring(sp, Position - sp); } protected void ws() { while ((ct & 0x0001) != 0) Position++; } #pragma warning restore IDE1006 protected char GetChar() { char r = cc; Position++; return r; } protected string GetIdentifier() { if ((ct & 0x0020) == 0) return ""; return tokenw(0x0010); } protected string GetNumber() { return tokenw(0x0040); } protected string GetString() { int sp = Position; do { if (cc == '\\') Position++; Position++; } while (ct != 0x0100); Position++; return Regex.Replace(_src.Substring(sp + 1, Position - sp - 2), @"\\(.)", "$1"); } protected PdtExpression GetExp() { var ins = new LinkedList(); int _; InterpretExp(ins, -2, out _); return new PdtExpression(ins); } readonly Dictionary defs = new Dictionary(); /// /// Creates an instance of the class. /// /// The source string. /// The binder. May be null. public PdtInterpreter(string src, Binder binder) { _src = src; _binder = binder; if (_binder == null) _binder = BinderAttribute.CreateBinderOfType(typeof(T)); } /// /// Interprets the source to an object of type . /// /// The interpreted object. public T Interpret() { InterpretDirectives(); return (T)InterpretObject(typeof(T)); } void InterpretDirectives() { bool flag = false; ws(); while (cc == '#') { Position++; switch (GetIdentifier()) { case "ver": ws(); Logger.Log("main", 3, "PDT", "Legacy PDT directive #ver={0} found. Ignoring.", GetNumber()); break; case "format": ws(); if (GetNumber() != "1") throw new NotSupportedException("Format not supported"); flag = true; break; case "define": if (!flag) throw new FormatException("Format directive not found"); ws(); string dname = GetIdentifier(); ws(); PdtExpression dexp = GetExp(); defs.Add(dname, dexp); break; default: throw new NotSupportedException("Unsupported directive found"); } ws(); } if (!flag) throw new FormatException("Format directive not found"); } object InterpretObject(Type type) { var result = ReflectionHelper.InvokeEmptyConstructor(type); bool dictflag = ReflectionHelper.IsGenericDictionary(type); while (true) { try { ws(); } catch (IndexOutOfRangeException) { return result; } object pkey = InterpretKey(type); char c = GetChar(); switch (c) { case '{': if (dictflag) { var ktype = type.GetGenericArguments()[0]; var ptype = type.GetGenericArguments()[1]; object key = _binder.ChangeType(pkey, ktype, null); object value = InterpretObject(ptype); ((IDictionary)result).Add(key, value); } else { MemberInfo prop; bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); Type ptype = ReflectionHelper.GetMemberType(prop); if (ReflectionHelper.IsGenericDictionary(ptype)) { var ktype = ptype.GetGenericArguments()[0]; var vtype = ptype.GetGenericArguments()[1]; if (flag) { object key = _binder.ChangeType(pkey, ktype, null); object value = InterpretObject(vtype); ((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); } else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); } else ReflectionHelper.SetValue(prop, result, InterpretObject(ptype)); } break; case ':': case ';': var exp = c == ';' ? _emptyexp : GetExp(); if (dictflag) { var ktype = type.GetGenericArguments()[0]; var vtype = type.GetGenericArguments()[1]; object key = _binder.ChangeType(pkey, ktype, null); object value = _binder.ChangeType(exp, vtype, null); ((IDictionary)result).Add(key, value); } else { MemberInfo prop; bool flag = ReflectionHelper.TryFindMemberWithAttribute(type, out prop); if (!flag && pkey is string) prop = ReflectionHelper.GetMember(type, (string)pkey); var ptype = ReflectionHelper.GetMemberType(prop); if (!typeof(IDictionary).IsAssignableFrom(ptype)) { object value = _binder.ChangeType(exp, ptype, null); ReflectionHelper.SetValue(prop, result, value, _binder); } else { var ktype = ptype.GetGenericArguments()[0]; var vtype = ptype.GetGenericArguments()[1]; object key = _binder.ChangeType(pkey, ktype, null); object value = _binder.ChangeType(exp, vtype, null); ((IDictionary)ReflectionHelper.GetValue(prop, result)).Add(key, value); } } break; case '}': return result; } } } protected virtual object InterpretKey(Type type) { return tokenb(0x1000).Trim(); } } }