/// <summary> /// Initialize with a span buffer /// </summary> /// <param name="buffer"></param> public XL19(Span <byte> buffer) { var header = MemoryMarshal.Read <XLHeader>(buffer); if (header.Magic != ((uint)DataType.XL & 0xFFFF) && header.Version != 0x13) { throw new InvalidOperationException("Not an XL stream"); } var offset = (int)header.TableOffset; var sz = SizeHelper.SizeOf <XLHeader>(); Types = MemoryMarshal.Cast <byte, XLType>(buffer.Slice(sz, header.Types)).ToArray(); for (var i = 0; i < header.Sets; i++) { List <object?> data = new List <object?>(); var locOffset = 0; var slice = buffer.Slice(offset); foreach (var type in Types) { switch (type) { case XLType.StringPointer: { data.Add(buffer.Slice(header.TableOffset + SpanHelper.ReadLittleInt(slice, ref locOffset)).ReadStringNonNull()); break; } case XLType.Int32: { data.Add(SpanHelper.ReadLittleInt(slice, ref locOffset)); break; } case XLType.Int16: { data.Add(SpanHelper.ReadLittleShort(slice, ref locOffset)); break; } case XLType.Int8: { data.Add(SpanHelper.ReadSByte(slice, ref locOffset)); break; } case XLType.UInt32: { data.Add(SpanHelper.ReadLittleUInt(slice, ref locOffset)); break; } case XLType.UInt16: { data.Add(SpanHelper.ReadLittleUShort(slice, ref locOffset)); break; } case XLType.UInt8: { data.Add(SpanHelper.ReadByte(slice, ref locOffset)); break; } case XLType.Single: { data.Add(SpanHelper.ReadLittleSingle(slice, ref locOffset)); break; } case XLType.NOP: data.Add(null); break; default: throw new NotImplementedException($"opcode {type:G}"); } } if (locOffset != header.Width) { Logger.Warn("XL", "Offset misaligned!"); } Entries.Add(data); offset += header.Width; } }
/// <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); }