public void EqualsWithSamePropertiesAndMemberNameArrayInstancesIsTrue() { ASClass class1 = new ASClass("abc", ASClassLayout.Normal, EmptyArray <string> .Instance); ASClass class2 = new ASClass("abc", ASClassLayout.Normal, EmptyArray <string> .Instance); Assert.AreNotEqual(class1, class2); }
protected virtual void WriteClassHashData(BinaryWriter hashInput, ASClass asClass) { ABCFile abc = asClass.ABC; WriteTraitsHashData(hashInput, asClass); WriteMethodHashData(hashInput, asClass.Constructor, true); WriteTraitsHashData(hashInput, asClass.Instance); WriteMethodHashData(hashInput, asClass.Instance.Constructor, true); string superClassObjName = asClass.Instance.SuperType?.ObjName; if (!string.IsNullOrWhiteSpace(superClassObjName) && superClassObjName != "Object") { ASClass superClass = abc .FindClassByName(superClassObjName); if (superClass != null) { WriteMultinameHashData(hashInput, asClass.Instance.SuperType); WriteClassHashData(hashInput, superClass); } } hashInput.Write((byte)asClass.Instance.ClassInfo); hashInput.Write((byte)asClass.Instance.Type.MultinameType); hashInput.Write((byte)asClass.Instance.ProtectedNamespace.NamespaceType); }
public void WriteObject_Objects_ClassDefinitionCaching_AMF3() { // Write out two untyped dynamic objects and two typed normal // objects and ensure the class definition is reused. ASObject untyped1 = new ASObject(); ASObject untyped2 = new ASObject(); ASClass @class = new ASClass("class", ASClassLayout.Normal, EmptyArray <string> .Instance); ASObject typed1 = new ASObject(@class); ASObject typed2 = new ASObject(@class); Mocks.ReplayAll(); output.ObjectEncoding = AMFObjectEncoding.AMF3; output.BeginObjectStream(); output.WriteObject(untyped1); output.WriteObject(typed1); output.WriteObject(untyped2); output.WriteObject(typed2); output.EndObjectStream(); byte[] expected = new byte[] { (byte)AMF0ObjectTypeCode.AMF3Data, (byte)AMF3ObjectTypeCode.Object, 0x0b, 0x01, 0x01, // untyped1 (byte)AMF3ObjectTypeCode.Object, 0x03, 0x0b, 0x63, 0x6c, 0x61, 0x73, 0x73, // typed1 (byte)AMF3ObjectTypeCode.Object, 0x01, 0x01, // untyped2 using cached class definition (byte)AMF3ObjectTypeCode.Object, 0x05, // typed2 using cached class definition }; CollectionAssert.AreElementsEqual(expected, stream.ToArray()); }
static IList <Tuple <ushort, string, ASInstance> > OrganizeByHash(IDictionary <ushort, ASClass> messages, HFlash flash, bool isOutgoing) { var organizedMessages = new List <Tuple <ushort, string, ASInstance> >(messages.Count); var hashedMessages = new Dictionary <string, List <Tuple <ushort, string, ASInstance> > >(); foreach (ushort header in messages.Keys) { ASClass messageClass = messages[header]; string hash = flash.GetHash(messageClass, ReferenceScan, isOutgoing); var messageData = new Tuple <ushort, string, ASInstance>( header, hash, messageClass.Instance); if (!hashedMessages.ContainsKey(hash)) { hashedMessages[hash] = new List <Tuple <ushort, string, ASInstance> >(); } hashedMessages[hash].Add(messageData); } return(hashedMessages.Values .OrderBy(l => l.Count) .SelectMany(l => l).ToList()); }
public void EqualsWithDifferentMemberOrderIsFalse() { ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" }); ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "def", "abc" }); Assert.AreNotEqual(class1, class2); }
protected override object MapObjectToNative(IActionScriptSerializer serializer, Type nativeType, ASClass @class, IEnumerable <IASValue> memberValues, IEnumerable <KeyValuePair <string, IASValue> > dynamicProperties, IExternalizable externalizableValue) { IDictionary <TKey, TValue> dict = CreateDictionaryInstance(@class.MemberNames.Count); // Add members. int memberIndex = 0; foreach (IASValue memberValue in memberValues) { TKey key = (TKey)Convert.ChangeType(@class.MemberNames[memberIndex], typeof(TKey)); TValue value = (TValue)serializer.ToNative(memberValue, typeof(TValue)); dict.Add(key, value); memberIndex += 1; } // Add dynamic properties. foreach (KeyValuePair <string, IASValue> pair in dynamicProperties) { TKey key = (TKey)Convert.ChangeType(pair.Key, typeof(TKey)); TValue value = (TValue)serializer.ToNative(pair.Value, typeof(TValue)); dict.Add(key, value); } return(dict); }
public void EqualsWithIdenticalInstancesIsTrue() { ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" }); ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" }); Assert.AreEqual(class1, class2); }
/// <summary> /// Retrieves a parsed class from its name /// </summary> /// <param name="cname">Class (short or full) name</param> /// <param name="inClass">Current class</param> /// <returns>A parsed class or an empty ASClass if the class is not found</returns> public ASClass GetClassByName(string cname, ASClass inClass) { ASClass aClass = new ASClass(); aClass.ClassName = cname; return(aClass); }
public override void SetUp() { base.SetUp(); externalizableClass = new ASClass("extern", ASClassLayout.Externalizable, EmptyArray <string> .Instance); externalizable = Mocks.CreateMock <IExternalizable>(); }
/// <summary> /// Retrieves a parsed class from its filename /// </summary> /// <param name="fileName">Class' file name</param> /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns> public ASClass GetClassByFile(string fileName) { ASClass aClass = new ASClass(); aClass.FileName = fileName; return(aClass); }
public string GetHash(ASClass asClass, bool referenceScan, bool isOutgoing) { using (var hashStream = new MemoryStream()) using (var hashInput = new BinaryWriter(hashStream)) { hashInput.Write(isOutgoing); WriteHashData(hashInput, asClass, isOutgoing); if (referenceScan) { ScanForMessageReferences(asClass.ABC); if (_messageReferencesCache.ContainsKey(asClass)) { List <Tuple <ASMethod, int> > messageReferences = _messageReferencesCache[asClass]; if (asClass.Instance.Type.ObjName == "RenderRoomMessageComposer") { } foreach (Tuple <ASMethod, int> messageReference in messageReferences) { ASMethod referencingMethod = messageReference.Item1; int referenceId = messageReference.Item2; WriteMethodHashData(hashInput, referencingMethod, false); hashInput.Write(referenceId); } } } return(GetHash(hashStream.ToArray())); } }
public void WriteObject_Objects_Externalizable_AMF3() { IExternalizable externalizableValue = Mocks.CreateMock <IExternalizable>(); externalizableValue.WriteExternal(output); LastCall.Do((WriteExternalDelegate) delegate(IDataOutput outputToUse) { // Note: outputToUse will be the same instance as output which we've already // tested so we don't need to try all combinations here. Just a few as a sanity check. outputToUse.WriteUTF("abc"); outputToUse.WriteInt(10); outputToUse.WriteObject(new ASString("def")); }); ASClass @class = new ASClass("class", ASClassLayout.Externalizable, EmptyArray <string> .Instance); ASExternalizableObject obj = new ASExternalizableObject(@class, externalizableValue); Mocks.ReplayAll(); output.ObjectEncoding = AMFObjectEncoding.AMF3; output.BeginObjectStream(); output.WriteObject(obj); output.EndObjectStream(); byte[] expected = new byte[] { (byte)AMF0ObjectTypeCode.AMF3Data, (byte)AMF3ObjectTypeCode.Object, 0x07, 0x0b, 0x63, 0x6c, 0x61, 0x73, 0x73, // class def 0x00, 0x03, 0x61, 0x62, 0x63, // write utf "abc" 0x00, 0x00, 0x00, 0x0a, // write int 10 (byte)AMF3ObjectTypeCode.String, 0x07, 0x64, 0x65, 0x66 // write object "def" }; CollectionAssert.AreElementsEqual(expected, stream.ToArray()); }
protected virtual void WriteHashData(BinaryWriter hashInput, ASClass asClass, bool isOutgoing) { if (isOutgoing) { string outgoingTypeName = asClass.Instance.Type.ObjName; if (outgoingTypeName.EndsWith("Composer")) { hashInput.Write(outgoingTypeName); return; } } else { ASClass parserClass = GetIncomingParser(asClass.Instance); if (parserClass != null) { WriteClassHashData(hashInput, parserClass); } } WriteClassHashData(hashInput, asClass); }
static string DumpMessages(string type, IDictionary <ushort, ASClass> messages) { string headerDump = string.Empty; bool isOutgoing = (type == "Outgoing"); IList <Tuple <ushort, string, ASInstance> > organizedMessages = OrganizeByHash(messages, Client, isOutgoing); foreach (Tuple <ushort, string, ASInstance> organizedMessage in organizedMessages) { ushort header = organizedMessage.Item1; string hash = organizedMessage.Item2; ASInstance instance = organizedMessage.Item3; string ctorSignature = instance.Constructor.ToString(); if (!isOutgoing) { ASClass parserClass = Client.GetIncomingParser(instance); ctorSignature += (", Parser: " + parserClass.Instance.Type.ObjName); } headerDump += $"{type}[{header}]({hash}): {instance.Type.ObjName}{ctorSignature}\r\n"; CountDuplicates(isOutgoing, hash); } return(headerDump.Trim()); }
private PacketValue[] GetOutgoingStructure(ASCode code, Local getLocal) { List <PacketValue> structure = new List <PacketValue>(); for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction == getLocal) { break; } if (!Local.IsGetLocal(instruction.OP)) { continue; } Local local = (Local)instruction; if (local.Register != getLocal.Register) { continue; } for (i += 1; i < code.Count; i++) { ASInstruction next = code[i]; if (next.OP != OPCode.CallPropVoid) { continue; } CallPropVoidIns callPropVoid = (CallPropVoidIns)next; if (callPropVoid.PropertyName.Name != "push") { continue; } ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetProperty) { ASClass classToCheck = Class; GetPropertyIns getProperty = (GetPropertyIns)previous; ASMultiname propertyName = getProperty.PropertyName; ASInstruction beforeGetProp = code[i - 2]; if (beforeGetProp.OP == OPCode.GetLex) { GetLexIns getLex = (GetLexIns)beforeGetProp; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetPacketValue(propertyName, classToCheck, out PacketValue piece)) { return(null); } structure.Add(piece); } } } return(structure.Count == 0 ? null : structure.ToArray()); }
private string GetOutgoingStructure(ASCode code, Local getLocal) { string structure = null; for (int i = 0; i < code.Count; i++) { ASInstruction instruction = code[i]; if (instruction == getLocal) { break; } if (!Local.IsGetLocal(instruction.OP)) { continue; } var local = (Local)instruction; if (local.Register != getLocal.Register) { continue; } for (i += 1; i < code.Count; i++) { ASInstruction next = code[i]; if (next.OP != OPCode.CallPropVoid) { continue; } var callPropVoid = (CallPropVoidIns)next; if (callPropVoid.PropertyName.Name != "push") { continue; } ASInstruction previous = code[i - 1]; if (previous.OP == OPCode.GetProperty) { ASClass classToCheck = Class; var getProperty = (GetPropertyIns)previous; ASMultiname propertyName = getProperty.PropertyName; ASInstruction beforeGetProp = code[i - 2]; if (beforeGetProp.OP == OPCode.GetLex) { var getLex = (GetLexIns)beforeGetProp; classToCheck = classToCheck.GetABC().GetClass(getLex.TypeName); } if (!TryGetStructurePiece(propertyName, classToCheck, out char piece)) { return(null); } structure += piece; } } } return(structure); }
/// <summary> /// Retrieves a parsed class from its filename /// </summary> /// <param name="fileName">Class' file name</param> /// <returns>A parsed class or an empty ASClass if the class is not found or invalid</returns> public ASClass FindClassFromFile(string fileName) { ASClass aClass = new ASClass(); aClass.FileName = fileName; return(aClass); }
/// <summary> /// Retrieves a parsed class from its name /// </summary> /// <param name="cname">Class (short or full) name</param> /// <param name="inClass">Current class</param> /// <returns>A parsed class or an empty ASClass if the class is not found</returns> public ASClass FindClassFromName(string cname, ASClass inClass) { ASClass aClass = new ASClass(); aClass.ClassName = cname; return(aClass); }
public void GetHashCodeIsSane() { // Compare hashcodes of two identical classes. ASClass class1 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" }); ASClass class2 = new ASClass("abc", ASClassLayout.Dynamic, new string[] { "abc", "def" }); Assert.AreEqual(class1.GetHashCode(), class2.GetHashCode()); }
public void Constructor(string className, ASClassLayout classLayout, string[] memberNames) { ASClass @class = new ASClass(className, classLayout, memberNames); Assert.AreSame(className, @class.ClassAlias); Assert.AreEqual(classLayout, @class.Layout); Assert.AreSame(memberNames, @class.MemberNames); }
static string DumpHeaders(HGame game, bool isDumpingOutgoing) { IReadOnlyDictionary <ushort, ASClass> messageClasses = (isDumpingOutgoing ? game.OutgoingMessages : game.IncomingMessages); IOrderedEnumerable <KeyValuePair <string, List <ushort> > > organizedHeaders = GetOrganizedHeadersByHashCount(game, messageClasses); string headersDump = string.Empty; string unusedHeadersDump = string.Empty; string messageType = (isDumpingOutgoing ? "Outgoing" : "Incoming"); var unusedHeaders = new List <KeyValuePair <string, List <ushort> > >(); foreach (KeyValuePair <string, List <ushort> > organizedHeader in organizedHeaders) { if (organizedHeader.Value.Count == 1) { if (isDumpingOutgoing) { UniqueOutMessageHashCount++; } else { UniqueInMessageHashCount++; } } string messageHash = organizedHeader.Key; foreach (ushort header in organizedHeader.Value) { ASClass messageClass = messageClasses[header]; string messageName = messageClass.Instance.QualifiedName.Name; ASMethod messageCtor = messageClass.Instance.Constructor; string dump = $"{messageType}[{header}, {messageHash}] = {messageName}{messageCtor}"; if (!isDumpingOutgoing) { ASClass inMsgParser = game.GetIncomingMessageParser(messageClass); dump += ($", Parser: {inMsgParser.Instance.QualifiedName.Name}"); } dump += "\r\n"; if (!game.IsMessageReferenced(messageClass)) { unusedHeadersDump += ("[Dead]" + dump); } else { headersDump += dump; } } } if (!string.IsNullOrWhiteSpace(unusedHeadersDump)) { headersDump += unusedHeadersDump; } return(headersDump.Trim()); }
/// <summary> /// Returns an enumerable containing references for the specified message class. /// </summary> /// <param name="messageClass">The message class being referenced.</param> /// <returns></returns> public IEnumerable <ASReference> GetMessageReferences(ASClass messageClass) { if (_messageReferences.ContainsKey(messageClass)) { return(_messageReferences[messageClass]); } return(null); }
/// <summary> /// Returns a value that determines whether the specified message class is an Outgoing type message class. /// </summary> /// <param name="messageClass">The message class to check whether it is an Outoing message class type.</param> /// <returns></returns> public bool IsMessageOutgoing(ASClass messageClass) { if (_isMessageOutgoing.ContainsKey(messageClass)) { return(_isMessageOutgoing[messageClass]); } return(false); }
public string GetHash(ASClass asClass) { using (var hashStream = new MemoryStream()) using (var hashInput = new BinaryWriter(hashStream)) { WriteClassHashData(hashInput, asClass); return(GetHash(hashStream.ToArray())); } }
private void LoadMessages() { ABCFile abc = ABCFiles.Last(); ASClass habboMessagesClass = abc.GetClass("HabboMessages"); if (habboMessagesClass == null) { IsPostShuffle = false; foreach (ASClass @class in abc.Classes) { if (@class.Traits.Count != 2 || @class.Traits[0].Type?.Name != "Map" || @class.Traits[1].Type?.Name != "Map") { continue; } if (@class.Instance.Traits.Count != 2) { continue; } habboMessagesClass = @class; break; } if (habboMessagesClass == null) { return; } } ASCode code = habboMessagesClass.Constructor.Body.ParseCode(); int outMapTypeIndex = habboMessagesClass.Traits[1].QNameIndex; ASInstruction[] instructions = code .Where(i => i.OP == OPCode.GetLex || i.OP == OPCode.PushShort || i.OP == OPCode.PushByte).ToArray(); for (int i = 0; i < instructions.Length; i += 3) { GetLexIns getLexInst = instructions[i + 0] as GetLexIns; bool isOutgoing = getLexInst?.TypeNameIndex == outMapTypeIndex; Primitive primitive = instructions[i + 1] as Primitive; ushort id = Convert.ToUInt16(primitive?.Value); getLexInst = instructions[i + 2] as GetLexIns; ASClass messageClass = abc.GetClass(getLexInst?.TypeName.Name); HMessage message = new HMessage(id, isOutgoing, messageClass); (isOutgoing ? OutMessages : InMessages).Add(id, message); if (!_messages.ContainsKey(messageClass)) { _messages.Add(messageClass, message); } } }
public void GetClassCachesInstances() { ASClass @class = ASClassCache.GetClass("abc", ASClassLayout.Dynamic, EmptyArray <string> .Instance); Assert.AreEqual("abc", @class.ClassAlias); Assert.AreEqual(ASClassLayout.Dynamic, @class.Layout); Assert.AreEqual(0, @class.MemberNames.Count); Assert.IsTrue(@class.MemberNames.IsReadOnly); Assert.AreSame(@class, ASClassCache.GetClass("abc", ASClassLayout.Dynamic, EmptyArray <string> .Instance)); }
/// <summary> /// Resolve wildcards in imports /// </summary> /// <param name="package">Package to explore</param> /// <param name="inClass">Current class</param> /// <param name="known">Packages already added</param> public void ResolveImports(string package, ASClass inClass, ArrayList known) { if (!known.Contains(package)) { known.Add(package); ASMember pMember = new ASMember(); pMember.Name = package + "*"; pMember.Type = package + "*"; inClass.Imports.Add(pMember); } }
/// <summary> /// Recursively convert classes /// </summary> /// <param name="path">folder to convert</param> static void ExploreFolder(string path) { currentFile = path; known.Add(path); // convert classes string[] files = Directory.GetFiles(path, "*.as"); ASClass fClass; string destFile; DateTime timestamp; int codepage; foreach (string file in files) { currentFile = file; destFile = destPath + file.Substring(srcPath.Length); // not modified: ignore timestamp = File.GetLastWriteTime(file); if (File.Exists(destFile) && File.GetLastWriteTime(destFile) == timestamp) { continue; } // parse class codepage = GetFileCodepage(file); fClass = new ASClass(); fClass.FileName = file; ASClassParser.ParseClass(fClass); if (fClass.IsVoid()) { continue; } // create intrinsic Directory.CreateDirectory(Path.GetDirectoryName(destFile)); Write(destFile, fClass.GenerateIntrinsic(), Encoding.GetEncoding(codepage)); File.SetCreationTime(destFile, timestamp); File.SetLastWriteTime(destFile, timestamp); total++; } // explore subfolders currentFile = path; string[] dirs = Directory.GetDirectories(path); foreach (string dir in dirs) { if (!known.Contains(dir)) { ExploreFolder(dir); } } }
public void Indexer() { ASClass @class = new ASClass("class", ASClassLayout.Dynamic, new string[] { "member" }); ASObject obj = new ASObject(@class); obj["member"] = new ASInt29(1); Assert.AreEqual(new ASInt29(1), obj["member"]); Assert.AreEqual(new ASInt29(1), obj.MemberValues[0]); obj["nonmember"] = new ASInt29(2); Assert.AreEqual(new ASInt29(2), obj["nonmember"]); Assert.AreEqual(new ASInt29(2), obj.DynamicProperties["nonmember"]); }
public void ConstructorWithClassAndMemberValues(ASClassLayout classLayout, string[] memberNames, int[] memberValues) { IASValue[] asMemberValues = WrapInts(memberValues); ASClass @class = new ASClass("class", classLayout, memberNames); ASObject obj = new ASObject(@class, asMemberValues); Assert.AreSame(@class, obj.Class); Assert.AreSame(asMemberValues, obj.MemberValues); Assert.AreEqual(0, obj.DynamicProperties.Count); Assert.AreEqual(classLayout == ASClassLayout.Normal, obj.DynamicProperties.IsReadOnly); }