// amf0 object object ReadObject() { var type = b.ReadUtf(); if (context.HasConcreteType(type)) { var instance = context.CreateInstance(type); var klass = context.GetClassInfo(instance); refs.Add(instance); foreach (var pair in ReadItems()) { if (klass.TryGetMember(pair.key, out var member)) { member.SetValue(instance, pair.value); } } return(instance); } else if (context.AsObjectFallback) { // object reference added in this.ReadAmf0AsObject() var obj = ReadAsObject(); obj.TypeName = type; return(obj); } else { throw new ArgumentException($"can't deserialize object: the type \"{type}\" isn't registered, and anonymous object fallback has been disabled"); } }
void WriteTypedObject(object value) { CheckDebug.NotNull(value); ReferenceAdd(value); var klass = context.GetClassInfo(value); WriteMarker(Marker.TypedObject); b.WriteUtfPrefixed(klass.Name); foreach (var member in klass.Members) { b.WriteUtfPrefixed(member.Name); WriteItem(member.GetValue(value)); } // object end is marked with a zero-length field name, and an end of object marker. b.WriteUInt16(0); WriteMarker(Marker.ObjectEnd); }
void WriteObject(object obj) { CheckDebug.NotNull(obj); WriteMarker(Marker.Object); if (ObjectReferenceAddOrWrite(obj)) { return; } var info = context.GetClassInfo(obj); if (refClasses.Add(info, out var index)) { // http://download.macromedia.com/pub/labs/amf/amf3_spec_121207.pdf // """ // The first (low) bit is a flag with value 1. The second bit is a flag // (representing whether a trait reference follows) with value 0 to imply that // this objects traits are being sent by reference. The remaining 1 to 27 // significant bits are used to encode a trait reference index (an integer). // -- AMF3 specification, 3.12 Object type // """ // <u27=trait-reference-index> <0=trait-reference> <1=object-inline> WriteInlineHeaderValue(index << 1); } else { // write the class definition // we can use the same format to serialize normal and extern classes, for simplicity's sake. // normal: <u25=member-count> <u1=dynamic> <0=externalizable> <1=trait-inline> <1=object-inline> // externalizable: <u25=insignificant> <u1=insignificant> <1=externalizable> <1=trait-inline> <1=object-inline> var header = info.Members.Length; header = (header << 1) | (info.IsDynamic ? 1 : 0); header = (header << 1) | (info.IsExternalizable ? 1 : 0); header = (header << 1) | 1; // the final shift is done here. WriteInlineHeaderValue(header); // write the type name UnmarkedWriteString(info.Name, isString: true); // then, write the actual object value if (info.IsExternalizable) { if (!(obj is IExternalizable externalizable)) { throw new ArgumentException($"{obj.GetType().FullName} ({info.Name}) is marked as externalizable but does not implement IExternalizable"); } externalizable.WriteExternal(new DataOutput(writer)); } else { foreach (var member in info.Members) { UnmarkedWriteString(member.Name, isString: true); } foreach (var member in info.Members) { WriteItem(member.GetValue(obj)); } if (info.IsDynamic) { if (!(obj is IDictionary <string, object> dictionary)) { throw new ArgumentException($"{obj.GetType()} is marked as dynamic but does not implement IDictionary"); } foreach (var(key, value) in dictionary) { UnmarkedWriteString(key, isString: true); WriteItem(value); } UnmarkedWriteString(string.Empty, isString: true); } } } }