/// <summary> /// Serializes a structure into a temporary memory block. /// </summary> /// <param name="context">The serialization context to use.</param> /// <param name="tagStream">The stream to write completed blocks of tag data to.</param> /// <param name="block">The temporary block to write incomplete tag data to.</param> /// <param name="info">Information about the tag structure type.</param> /// <param name="structure">The structure to serialize.</param> /// <exception cref="System.InvalidOperationException">Structure type must have TagStructureAttribute</exception> private void SerializeStruct(ISerializationContext context, MemoryStream tagStream, IDataBlock block, TagStructureInfo info, object structure) { var baseOffset = block.Stream.Position; var enumerator = new TagFieldEnumerator(info); while (enumerator.Next()) { SerializeProperty(context, tagStream, block, structure, enumerator, baseOffset); } // Honor the struct size if it's defined if (info.TotalSize > 0) { block.Stream.Position = baseOffset + info.TotalSize; if (block.Stream.Position > block.Stream.Length) { block.Stream.SetLength(block.Stream.Position); } } // Honor alignment if (info.Structure.Align > 0) { block.SuggestAlignment(info.Structure.Align); } }
/// <summary> /// Deserializes a structure. /// </summary> /// <param name="reader">The reader.</param> /// <param name="context">The serialization context to use.</param> /// <param name="info">Information about the structure to deserialize.</param> /// <returns>The deserialized structure.</returns> /// <exception cref="System.InvalidOperationException">Target type must have TagStructureAttribute</exception> private object DeserializeStruct(BinaryReader reader, ISerializationContext context, TagStructureInfo info) { var baseOffset = reader.BaseStream.Position; var instance = Activator.CreateInstance(info.Types[0]); var enumerator = new TagFieldEnumerator(info); while (enumerator.Next()) { DeserializeProperty(reader, context, instance, enumerator, baseOffset); } if (enumerator.Info.TotalSize > 0) { reader.BaseStream.Position = baseOffset + enumerator.Info.TotalSize; } return(instance); }
public override bool Execute(List<string> args) { if (args.Count > 1) return false; var match = (args.Count == 1); var token = match ? args[0].ToLower() : ""; var enumerator = new TagFieldEnumerator(Structure); while (enumerator.Next()) { var nameString = enumerator.Field.Name; if (match && !nameString.ToLower().Contains(token)) continue; var fieldType = enumerator.Field.FieldType; var fieldValue = enumerator.Field.GetValue(Value); var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; string valueString; if (fieldValue == null) valueString = "null"; else if (fieldType.GetInterface(typeof(IList).Name) != null) valueString = ((IList)fieldValue).Count != 0 ? $"{{...}}[{((IList)fieldValue).Count}]" : "null"; else if (fieldType == typeof(StringID)) valueString = Info.StringIDs.GetString((StringID)fieldValue); else if (fieldType == typeof(TagInstance)) valueString = $"[0x{((TagInstance)fieldValue).Index:X4}] {Info.TagNames[((TagInstance)fieldValue).Index]}.{Info.StringIDs.GetString(((TagInstance)fieldValue).Group.Name)}"; else valueString = fieldValue.ToString(); Console.WriteLine("{0}: {1} = {2}", nameString, typeString, valueString); } return true; }
/// <summary> /// Serializes a structure into a temporary memory block. /// </summary> /// <param name="context">The serialization context to use.</param> /// <param name="tagStream">The stream to write completed blocks of tag data to.</param> /// <param name="block">The temporary block to write incomplete tag data to.</param> /// <param name="info">Information about the tag structure type.</param> /// <param name="structure">The structure to serialize.</param> /// <exception cref="System.InvalidOperationException">Structure type must have TagStructureAttribute</exception> private void SerializeStruct(ISerializationContext context, MemoryStream tagStream, IDataBlock block, TagStructureInfo info, object structure) { var baseOffset = block.Stream.Position; var enumerator = new TagFieldEnumerator(info); while (enumerator.Next()) SerializeProperty(context, tagStream, block, structure, enumerator, baseOffset); // Honor the struct size if it's defined if (info.TotalSize > 0) { block.Stream.Position = baseOffset + info.TotalSize; if (block.Stream.Position > block.Stream.Length) block.Stream.SetLength(block.Stream.Position); } // Honor alignment if (info.Structure.Align > 0) block.SuggestAlignment(info.Structure.Align); }
/// <summary> /// Serializes a property. /// </summary> /// <param name="context">The serialization context to use.</param> /// <param name="tagStream">The stream to write completed blocks of tag data to.</param> /// <param name="block">The temporary block to write incomplete tag data to.</param> /// <param name="instance">The object that the property belongs to.</param> /// <param name="structInfo">The structure information.</param> /// <param name="property">The property.</param> /// <param name="baseOffset">The base offset of the structure from the start of its block.</param> /// <exception cref="System.InvalidOperationException">Offset for property \ + property.Name + \ is outside of its structure</exception> private void SerializeProperty(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object instance, TagFieldEnumerator enumerator, long baseOffset) { // Seek to the value if it has an offset specified and write it var valueInfo = enumerator.Attribute; if (enumerator.Attribute.Offset >= 0) block.Stream.Position = baseOffset + valueInfo.Offset; var startOffset = block.Stream.Position; var val = enumerator.Field.GetValue(instance); SerializeValue(context, tagStream, block, val, valueInfo, enumerator.Field.FieldType); if (valueInfo.Size > 0) block.Stream.Position = startOffset + valueInfo.Size; }
public override bool Execute(List<string> args) { if (args.Count < 1 || args.Count > 2) return false; var blockName = args[0]; var ownerType = Owner.GetType(); var enumerator = new TagFieldEnumerator(Structure); var deferredNames = new List<string>(); var deferredArgs = new List<string>(); if (blockName.Contains(".")) { deferredNames.AddRange(blockName.Split('.')); blockName = deferredNames[0]; deferredNames = deferredNames.Skip(1).ToList(); deferredArgs.AddRange(args.Skip(1)); args = new List<string> { blockName }; } if (blockName.Contains("]")) { var openBracketIndex = blockName.IndexOf('['); var closeBracketIndex = blockName.IndexOf(']'); var name = blockName.Substring(0, openBracketIndex); var index = blockName.Substring(openBracketIndex + 1, (closeBracketIndex - openBracketIndex) - 1); blockName = name; args = new List<string> { name, index }; } var blockNameLow = blockName.ToLower(); var field = enumerator.Find(f => f.Name == blockName || f.Name.ToLower() == blockNameLow); if (field == null) { Console.WriteLine("{0} does not contain a block named \"{1}\"", ownerType.Name, blockName); return false; } var contextName = ""; object blockValue = null; var structureAttribute = field.FieldType.CustomAttributes.ToList().Find(a => a.AttributeType == typeof(TagStructureAttribute)); if (structureAttribute != null) { if (args.Count != 1) return false; blockValue = field.GetValue(Owner); contextName = $"{blockName}"; } else { if (args.Count != 2) return false; IList fieldValue = null; if (field.FieldType.GetInterface("IList") == null || (fieldValue = (IList)field.GetValue(Owner)) == null) { Console.WriteLine("{0} does not contain a block named \"{1}\"", ownerType.Name, blockName); return false; } int blockIndex = 0; if (args[1] == "*") blockIndex = fieldValue.Count - 1; else if (!int.TryParse(args[1], out blockIndex)) { Console.WriteLine("Invalid index requested from block {0}: {1}", blockName, blockIndex); return false; } if (blockIndex >= fieldValue.Count || blockIndex < 0) { Console.WriteLine("Invalid index requested from block {0}: {1}", blockName, blockIndex); return false; } blockValue = fieldValue[blockIndex]; contextName = $"{blockName}[{blockIndex}]"; } var blockStructure = new TagStructureInfo(blockValue.GetType()); var blockContext = new CommandContext(Stack.Context, contextName); blockContext.AddCommand(new ListFieldsCommand(Info, blockStructure, blockValue)); blockContext.AddCommand(new SetFieldCommand(Stack, Info, Tag, blockStructure, blockValue)); blockContext.AddCommand(new EditBlockCommand(Stack, Info, Tag, blockValue)); blockContext.AddCommand(new AddToCommand(Stack, Info, Tag, blockStructure, blockValue)); blockContext.AddCommand(new RemoveFromCommand(Stack, Info, Tag, blockStructure, blockValue)); blockContext.AddCommand(new CopyElementsCommand(Stack, Info, Tag, blockStructure, blockValue)); blockContext.AddCommand(new PasteElementsCommand(Stack, Info, Tag, blockStructure, blockValue)); blockContext.AddCommand(new ExitToCommand(Stack)); Stack.Push(blockContext); if (deferredNames.Count != 0) { var name = deferredNames[0]; deferredNames = deferredNames.Skip(1).ToList(); foreach (var deferredName in deferredNames) name += '.' + deferredName; args = new List<string> { name }; args.AddRange(deferredArgs); var command = new EditBlockCommand(Stack, Info, Tag, blockValue); return command.Execute(args); } return true; }
/// <summary> /// Deserializes a property of a structure. /// </summary> /// <param name="reader">The reader.</param> /// <param name="context">The serialization context to use.</param> /// <param name="instance">The instance to store the property to.</param> /// <param name="enumerator">The active element enumerator.</param> /// <param name="baseOffset">The offset of the start of the structure.</param> /// <exception cref="System.InvalidOperationException">Offset for property is outside of its structure</exception> private void DeserializeProperty(BinaryReader reader, ISerializationContext context, object instance, TagFieldEnumerator enumerator, long baseOffset) { // Seek to the value if it has an offset specified and then read it if (enumerator.Attribute.Offset >= 0) { reader.BaseStream.Position = baseOffset + enumerator.Attribute.Offset; } var startOffset = reader.BaseStream.Position; enumerator.Field.SetValue(instance, DeserializeValue(reader, context, enumerator.Attribute, enumerator.Field.FieldType)); if (enumerator.Attribute.Size > 0) { reader.BaseStream.Position = startOffset + enumerator.Attribute.Size; // Honor the value's size if it has one set } }
/// <summary> /// Serializes a property. /// </summary> /// <param name="context">The serialization context to use.</param> /// <param name="tagStream">The stream to write completed blocks of tag data to.</param> /// <param name="block">The temporary block to write incomplete tag data to.</param> /// <param name="instance">The object that the property belongs to.</param> /// <param name="structInfo">The structure information.</param> /// <param name="property">The property.</param> /// <param name="baseOffset">The base offset of the structure from the start of its block.</param> /// <exception cref="System.InvalidOperationException">Offset for property \ + property.Name + \ is outside of its structure</exception> private void SerializeProperty(ISerializationContext context, MemoryStream tagStream, IDataBlock block, object instance, TagFieldEnumerator enumerator, long baseOffset) { // Seek to the value if it has an offset specified and write it var valueInfo = enumerator.Attribute; if (enumerator.Attribute.Offset >= 0) { block.Stream.Position = baseOffset + valueInfo.Offset; } var startOffset = block.Stream.Position; var val = enumerator.Field.GetValue(instance); SerializeValue(context, tagStream, block, val, valueInfo, enumerator.Field.FieldType); if (valueInfo.Size > 0) { block.Stream.Position = startOffset + valueInfo.Size; } }
public override bool Execute(List<string> args) { if (args.Count < 2) return false; var fieldName = args[0]; var fieldNameLow = fieldName.ToLower(); var previousContext = Stack.Context; var previousOwner = Owner; var previousStructure = Structure; if (fieldName.Contains(".")) { var lastIndex = fieldName.LastIndexOf('.'); var blockName = fieldName.Substring(0, lastIndex); fieldName = fieldName.Substring(lastIndex + 1, (fieldName.Length - lastIndex) - 1); fieldNameLow = fieldName.ToLower(); var command = new EditBlockCommand(Stack, Info, Tag, Owner); if (!command.Execute(new List<string> { blockName })) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } command = (Stack.Context.GetCommand("Edit") as EditBlockCommand); Owner = command.Owner; Structure = command.Structure; if (Owner == null) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } } var enumerator = new TagFieldEnumerator(Structure); var field = enumerator.Find(f => f.Name == fieldName || f.Name.ToLower() == fieldNameLow); if (field == null) { Console.WriteLine("ERROR: {0} does not contain a field named \"{1}\".", Structure.Types[0].Name, fieldName); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } var fieldType = field.FieldType; var fieldValue = ParseArgs(field.FieldType, args.Skip(1).ToList()); if (fieldValue != null && fieldValue.Equals(false)) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } field.SetValue(Owner, fieldValue); var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; var valueString = fieldType == typeof(StringID) ? Info.StringIDs.GetString((StringID)fieldValue) : fieldType.GetInterface(typeof(IList).Name) != null ? (((IList)fieldValue).Count != 0 ? $"{{...}}[{((IList)fieldValue).Count}]" : "null") : fieldValue == null ? "null" : fieldValue.ToString(); Console.WriteLine("{0}: {1} = {2}", field.Name, typeString, valueString); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return true; }
public override bool Execute(List<string> args) { if (args.Count < 1 || args.Count > 3) return false; var fieldName = args[0]; var fieldNameLow = fieldName.ToLower(); var previousContext = Stack.Context; var previousOwner = Owner; var previousStructure = Structure; if (fieldName.Contains(".")) { var lastIndex = fieldName.LastIndexOf('.'); var blockName = fieldName.Substring(0, lastIndex); fieldName = fieldName.Substring(lastIndex + 1, (fieldName.Length - lastIndex) - 1); fieldNameLow = fieldName.ToLower(); var command = new EditBlockCommand(Stack, Info, Tag, Owner); if (!command.Execute(new List<string> { blockName })) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } command = (Stack.Context.GetCommand("Edit") as EditBlockCommand); Owner = command.Owner; Structure = command.Structure; if (Owner == null) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } } var enumerator = new TagFieldEnumerator(Structure); var field = enumerator.Find(f => f.Name == fieldName || f.Name.ToLower() == fieldNameLow); var fieldType = field.FieldType; if ((field == null) || (!fieldType.IsGenericType) || (fieldType.GetInterface("IList") == null)) { Console.WriteLine("ERROR: {0} does not contain a tag block named \"{1}\".", Structure.Types[0].Name, args[0]); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } var blockValue = field.GetValue(Owner) as IList; if (blockValue == null) { blockValue = Activator.CreateInstance(field.FieldType) as IList; field.SetValue(Owner, blockValue); } var elementType = field.FieldType.GenericTypeArguments[0]; var index = blockValue.Count - 1; var count = 1; var genericIndex = false; var genericCount = false; if (args.Count == 1) { count = 1; } else { if (args.Count >= 2) { if (args[1] == "*") { genericIndex = true; index = blockValue.Count; } else if (!int.TryParse(args[1], out index) || index < 0 || index >= blockValue.Count) { Console.WriteLine($"Invalid index specified: {args[1]}"); return false; } } if (args.Count == 3) { if (args[2] == "*") { genericCount = true; count = blockValue.Count - index; } else if (!int.TryParse(args[2], out count) || count < 1) { Console.WriteLine($"Invalid number specified: {args[2]}"); return false; } } } if (genericIndex && genericCount) { index = 0; count = blockValue.Count; } else if (genericIndex) { index -= count; if (index < 0) index = 0; } if (index + count > blockValue.Count) { Console.WriteLine($"ERROR: Too many block elements specified to be removed: {count}. Maximum at index {index} can be {blockValue.Count - index}"); return false; } for (var i = 0; i < count; i++) blockValue.RemoveAt(index); field.SetValue(Owner, blockValue); var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; var itemString = count < 2 ? "element" : "elements"; var valueString = ((IList)blockValue).Count != 0 ? $"{{...}}[{((IList)blockValue).Count}]" : "null"; Console.WriteLine($"Successfully removed {count} {itemString} from {field.Name} at index {index}: {typeString}"); Console.WriteLine(valueString); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return true; }
public override bool Execute(List<string> args) { if (args.Count < 1 || args.Count > 2) return false; if (CopyElementsCommand.Elements == null) { Console.WriteLine("ERROR: No elements are available in the clipboard."); return false; } var fieldName = args[0]; var fieldNameLow = fieldName.ToLower(); var previousContext = Stack.Context; var previousOwner = Owner; var previousStructure = Structure; if (fieldName.Contains(".")) { var lastIndex = fieldName.LastIndexOf('.'); var blockName = fieldName.Substring(0, lastIndex); fieldName = fieldName.Substring(lastIndex + 1, (fieldName.Length - lastIndex) - 1); fieldNameLow = fieldName.ToLower(); var command = new EditBlockCommand(Stack, Info, Tag, Owner); if (!command.Execute(new List<string> { blockName })) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } command = (Stack.Context.GetCommand("Edit") as EditBlockCommand); Owner = command.Owner; Structure = command.Structure; if (Owner == null) { while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } } var index = -1; if (args.Count > 1) { if (args[1] != "*" && (!int.TryParse(args[1], out index) || index < 0)) { Console.WriteLine($"Invalid index specified: {args[1]}"); return false; } } var enumerator = new TagFieldEnumerator(Structure); var field = enumerator.Find(f => f.Name == fieldName || f.Name.ToLower() == fieldNameLow); var fieldType = field.FieldType; if ((field == null) || (!fieldType.IsGenericType) || (fieldType.GetInterface("IList") == null)) { Console.WriteLine("ERROR: {0} does not contain a tag block named \"{1}\".", Structure.Types[0].Name, args[0]); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return false; } var elementType = field.FieldType.GenericTypeArguments[0]; if (elementType != CopyElementsCommand.ElementType) { Console.WriteLine("Invalid block element type!"); return false; } var blockValue = field.GetValue(Owner) as IList; if (blockValue == null) { blockValue = Activator.CreateInstance(field.FieldType) as IList; field.SetValue(Owner, blockValue); } if (index > blockValue.Count) { Console.WriteLine($"Invalid index specified: {args[2]}"); return false; } for (var i = 0; i < CopyElementsCommand.Elements.Count; i++) { var element = CopyElementsCommand.Elements[i]; if (index == -1) blockValue.Add(element); else blockValue.Insert(index + i, element); } field.SetValue(Owner, blockValue); var typeString = fieldType.IsGenericType ? $"{fieldType.Name}<{fieldType.GenericTypeArguments[0].Name}>" : fieldType.Name; var itemString = CopyElementsCommand.Elements.Count < 2 ? "element" : "elements"; var valueString = ((IList)blockValue).Count != 0 ? $"{{...}}[{((IList)blockValue).Count}]" : "null"; Console.WriteLine($"Successfully pasted {CopyElementsCommand.Elements.Count} {itemString} to {field.Name}: {typeString}"); Console.WriteLine(valueString); while (Stack.Context != previousContext) Stack.Pop(); Owner = previousOwner; Structure = previousStructure; return true; }
private object CreateElement(Type elementType) { var element = Activator.CreateInstance(elementType); var isTagStructure = Attribute.IsDefined(elementType, typeof(TagStructureAttribute)); if (isTagStructure) { var enumerator = new TagFieldEnumerator( new TagStructureInfo(elementType)); while (enumerator.Next()) { var fieldType = enumerator.Field.FieldType; if (fieldType.IsArray && enumerator.Attribute.Count > 0) { var array = (IList)Activator.CreateInstance(enumerator.Field.FieldType, new object[] { enumerator.Attribute.Count }); for (var i = 0; i < enumerator.Attribute.Count; i++) array[i] = CreateElement(fieldType.GetElementType()); } else { try { enumerator.Field.SetValue(element, CreateElement(enumerator.Field.FieldType)); } catch { enumerator.Field.SetValue(element, null); } } } } return element; }