CodeNode GenerateArrayAssignment(KeyValuePair <FieldLayoutAttribute, PropertyInfo> pair) { var fieldType = pair.Key.FieldType; bool isNibbleArray = pair.Key is NibbleArrayFieldLayoutAttribute; int lengthIndex = ((ArrayFieldLayoutAttribute)pair.Key).ArrayLengthFieldIndex; //we can skip entirely if the length field was zero //we'll combine this as part of the "reading" of the field var parseConditionNode = new SkipArrayAssignmentIfLengthIsZeroNode(lengthIndex); //find out if we should even parse this field if (pair.Value != null && !ShouldParseField(pair.Value.Name)) { //we can simply return this skip node since it effectively encapsulates the length check as well return(new SkipTypeNode(fieldType.MakeArrayType(), lengthIndex)); } else { var readNode = new ReadTypeNode(fieldType.MakeArrayType(), lengthIndex, isNibble: isNibbleArray); BlockNode assignmentBlock = null; if (pair.Value != null) { assignmentBlock = new BlockNode(new AssignFieldToPropertyNode(fieldType.MakeArrayType(), pair.Value)); } //return a FieldAssignmentNode. Note we're combining the parseConditionNode and the readNode. return(new FieldAssignmentNode(fieldType.MakeArrayType(), pair.Key.FieldIndex, new BlockNode(parseConditionNode, readNode), assignmentBlock)); } }
public override CodeNode VisitReadType(ReadTypeNode node) { _Writer.WriteStartElement("ReadType"); _Writer.WriteAttributeString("IsNibble", node.IsNibble.ToString()); _Writer.WriteAttributeString("LengthIndex", node.LengthIndex.ToString()); _Writer.WriteAttributeString("Type", node.Type.ToString()); _Writer.WriteEndElement(); return(node); }
public override CodeNode VisitReadType(ReadTypeNode node) { if (_FieldLocal == null) { throw new InvalidOperationException("Cannot read string outside a FieldAssignmentNode"); } MethodInfo readTypeMethod; var argsArray = node.Type.IsArray ? new[] { typeof(int) } : new Type[0]; if (node.IsNibble) { readTypeMethod = typeof(BinaryReader).GetMethod("ReadNibbleArray", argsArray); } else if (!_ReadTypeMethods.TryGetValue(node.Type, out readTypeMethod)) { string readTypeMethodName; if (node.Type == typeof(byte)) { readTypeMethodName = "ReadByte"; } else if (node.Type == typeof(byte[])) { readTypeMethodName = "ReadByteArray"; } else if (node.Type == typeof(sbyte)) { readTypeMethodName = "ReadSByte"; } else if (node.Type == typeof(sbyte[])) { readTypeMethodName = "ReadSByteArray"; } else if (node.Type == typeof(ushort)) { readTypeMethodName = "ReadUInt16"; } else if (node.Type == typeof(ushort[])) { readTypeMethodName = "ReadUInt16Array"; } else if (node.Type == typeof(short)) { readTypeMethodName = "ReadInt16"; } else if (node.Type == typeof(short[])) { readTypeMethodName = "ReadInt16Array"; } else if (node.Type == typeof(uint)) { readTypeMethodName = "ReadUInt32"; } else if (node.Type == typeof(uint[])) { readTypeMethodName = "ReadUInt32Array"; } else if (node.Type == typeof(int)) { readTypeMethodName = "ReadInt32"; } else if (node.Type == typeof(int[])) { readTypeMethodName = "ReadInt32Array"; } else if (node.Type == typeof(ulong)) { readTypeMethodName = "ReadUInt64"; } else if (node.Type == typeof(ulong[])) { readTypeMethodName = "ReadUInt64Array"; } else if (node.Type == typeof(long)) { readTypeMethodName = "ReadInt64"; } else if (node.Type == typeof(long[])) { readTypeMethodName = "ReadInt64Array"; } else if (node.Type == typeof(float)) { readTypeMethodName = "ReadSingle"; } else if (node.Type == typeof(float[])) { readTypeMethodName = "ReadSingleArray"; } else if (node.Type == typeof(double)) { readTypeMethodName = "ReadDouble"; } else if (node.Type == typeof(double[])) { readTypeMethodName = "ReadDoubleArray"; } else if (node.Type == typeof(string)) { readTypeMethodName = "ReadString"; } else if (node.Type == typeof(string[])) { readTypeMethodName = "ReadStringArray"; } else if (node.Type == typeof(DateTime)) { readTypeMethodName = "ReadDateTime"; } else if (node.Type == typeof(BitArray)) { readTypeMethodName = "ReadBitArray"; } else { throw new NotSupportedException(string.Format(Resources.UnsupportedReaderType, node.Type)); } readTypeMethod = typeof(BinaryReader).GetMethod(readTypeMethodName, argsArray); _ReadTypeMethods[node.Type] = readTypeMethod; } Log($"Reading with {readTypeMethod.Name}."); ILGen.Ldloc(_Reader); //if we have a length index, load its local (we enforce its presence for arrays in the node) if (node.LengthIndex.HasValue) { ILGen.Ldloc(_FieldLocals[node.LengthIndex.Value]); } ILGen.Callvirt(readTypeMethod); ILGen.Stloc(_FieldLocal); return(node); }
CodeNode GenerateAssignment(KeyValuePair <FieldLayoutAttribute, PropertyInfo> pair) { var fieldType = pair.Key.FieldType; //if this is an array, defer to GenerateArrayAssignment if (pair.Key is ArrayFieldLayoutAttribute) { // TODO: Why do we need these fieldType checks at all? if (fieldType == typeof(string)) { // TODO: Accept string arrays throw new InvalidOperationException(Resources.NoStringArrays); } if (fieldType == typeof(BitArray)) { throw new InvalidOperationException(Resources.NoBitArrayArrays); } return(GenerateArrayAssignment(pair)); } //get the length if this is a fixed-length string var stringLength = -1; if (pair.Key is StringFieldLayoutAttribute stringLayout && stringLayout.Length > 0) { stringLength = stringLayout.Length; } //just skip this field if we have an assignment, but shouldn't be parsing it if (pair.Value != null && !ShouldParseField(pair.Value.Name)) { if (stringLength > 0) { return(new SkipRawBytesNode(stringLength)); } else { return(new SkipTypeNode(fieldType)); } } //determine how we'll read the field CodeNode readerNode; if (stringLength > 0) { readerNode = new ReadFixedStringNode(stringLength); } else { readerNode = new ReadTypeNode(fieldType); } BlockNode assignmentBlock = null; //if we have a property to assign to, generate the appropriate assignment statements if (pair.Value != null) { var assignmentNodes = new List <CodeNode>(); //if this is optional, set us up to skip if the missing flag is set if (pair.Key is FlaggedFieldLayoutAttribute optionalLayout) { assignmentNodes.Add(new SkipAssignmentIfFlagSetNode(optionalLayout.FlagIndex, optionalLayout.FlagMask)); } //if we have a missing value, set us up to skip if the value matches the missing value else if (pair.Key.MissingValue != null && !pair.Key.PersistMissingValue) { if (!(fieldType.IsAssignableFrom(pair.Key.MissingValue.GetType()))) { throw new InvalidOperationException(string.Format("Missing value {0} is not assignable to {1}.", pair.Key.MissingValue, fieldType)); } assignmentNodes.Add(new SkipAssignmentIfMissingValueNode(pair.Key.MissingValue)); } //set us up to assign to the property assignmentNodes.Add(new AssignFieldToPropertyNode(fieldType, pair.Value)); assignmentBlock = new BlockNode(assignmentNodes); } return(new FieldAssignmentNode(fieldType, pair.Key.FieldIndex, readerNode, assignmentBlock)); }
public virtual CodeNode VisitReadType(ReadTypeNode node) { return(node); }