/// <summary> /// Initialize with a span buffer /// </summary> /// <param name="buffer"></param> /// <param name="t"></param> public XL20(Span <byte> buffer, Type t) { var header = MemoryMarshal.Read <XLHeader>(buffer); if (header.Magic != ((uint)DataType.XL & 0xFFFF) && header.Version != 0x14) { throw new InvalidOperationException("Not an XL stream"); } UnderlyingType = t; var offset = (int)header.TableOffset; var properties = t.GetProperties(); for (var i = 0; i < header.FileSize; i++) { var instance = Activator.CreateInstance(t); var localOffset = 0; var slice = buffer.Slice(offset); foreach (var property in properties) { var type = property.PropertyType; object?value; switch (type.FullName) { case "System.Int64": value = SpanHelper.ReadLittleLong(slice, ref localOffset); break; case "System.Int32": value = SpanHelper.ReadLittleInt(slice, ref localOffset); break; case "System.Int16": value = SpanHelper.ReadLittleShort(slice, ref localOffset); break; case "System.UInt64": value = SpanHelper.ReadLittleULong(slice, ref localOffset); break; case "System.UInt32": value = SpanHelper.ReadLittleUInt(slice, ref localOffset); break; case "System.UInt16": value = SpanHelper.ReadLittleUShort(slice, ref localOffset); break; case "System.Int8": case "System.SByte": value = SpanHelper.ReadSByte(slice, ref localOffset); break; case "System.UInt8": case "System.Byte": value = SpanHelper.ReadByte(slice, ref localOffset); break; case "System.Single": value = SpanHelper.ReadLittleSingle(slice, ref localOffset); break; case "System.Double": value = SpanHelper.ReadLittleDouble(slice, ref localOffset); break; case "System.Decimal": value = SpanHelper.ReadLittleDecimal(slice, ref localOffset); break; case "System.Boolean": value = SpanHelper.ReadByte(slice, ref localOffset) == 1; break; case "System.String": { var stringSize = property.GetCustomAttribute <StringLengthAttribute>(); var size = stringSize?.MaximumLength ?? SpanHelper.ReadLittleInt(slice, ref localOffset); value = size > 0 ? Encoding.UTF8.GetString(slice.Slice(localOffset, size)) : null; if (stringSize != null && value is string stringValue) { value = stringValue.TrimEnd('\u0000'); } localOffset += size; break; } default: throw new NotImplementedException(type.FullName); } property.SetValue(instance, value); } Entries.Add(instance); offset += localOffset; } }
/// <summary> /// Cast all entries to the specified struct type. /// </summary> /// <param name="t"></param> /// <returns></returns> public List <object?> Cast(Type t) { var entries = new List <object?>(); var properties = t.GetProperties(); var count = Math.Min(Header.FieldCount, properties.Length); foreach (var buffer in Entries) { var slice = buffer.Span; var instance = Activator.CreateInstance(t); var localOffset = 0; for (var index = 0; index < count; index++) { var property = properties[index]; var type = property.PropertyType; object?value; switch (type.FullName) { case "System.Int64": value = SpanHelper.ReadLittleLong(slice, ref localOffset); break; case "System.Int32": value = SpanHelper.ReadLittleInt(slice, ref localOffset); break; case "System.Int16": value = SpanHelper.ReadLittleShort(slice, ref localOffset); break; case "System.UInt64": value = SpanHelper.ReadLittleULong(slice, ref localOffset); break; case "System.UInt32": value = SpanHelper.ReadLittleUInt(slice, ref localOffset); break; case "System.UInt16": value = SpanHelper.ReadLittleUShort(slice, ref localOffset); break; case "System.Int8": case "System.SByte": value = SpanHelper.ReadSByte(slice, ref localOffset); break; case "System.UInt8": case "System.Byte": value = SpanHelper.ReadByte(slice, ref localOffset); break; case "System.Single": value = SpanHelper.ReadLittleSingle(slice, ref localOffset); break; case "System.Double": value = SpanHelper.ReadLittleDouble(slice, ref localOffset); break; case "System.Boolean": value = SpanHelper.ReadByte(slice, ref localOffset) == 1; break; case "System.String": { var offset = SpanHelper.ReadLittleInt(slice, ref localOffset); value = null; var resolvedSize = DynamicData.Length - SizeHelper.SizeOf <ECBStringHeader>(); if (offset >= 0 && resolvedSize >= 0 && offset < resolvedSize) { var stringHeader = MemoryMarshal.Read <ECBStringHeader>(DynamicData.Span.Slice(offset)); Logger.Assert(stringHeader.CharSet == ECBCharSet.UTF8, "CharSet == ECBCharSet.UTF8"); if (stringHeader.Size > 1) { value = Encoding.UTF8.GetString(DynamicData.Span.Slice(offset + SizeHelper.SizeOf <ECBStringHeader>(), stringHeader.Size - 1)); } } break; } default: throw new NotImplementedException(type.FullName); } property.SetValue(instance, value); } entries.Add(instance); } return(entries); }