@@ -595,25 +595,11 @@ public static ref D2SaveLayout From(Span<byte> data)
595595 return ref layout ;
596596 }
597597
598- /// <summary>
599- /// Gets a reference to the layout from a byte array.
600- /// Throws InvalidDataException if magic values are invalid or version is >= 104.
601- /// For v104+ saves, use <see cref="D2SaveLayoutV104.From(byte[])"/> instead.
602- /// </summary>
603- public static ref D2SaveLayout From ( byte [ ] data )
604- => ref From ( data . AsSpan ( ) ) ;
605-
606598 /// <summary>
607599 /// Updates the checksum in the provided data buffer.
608600 /// </summary>
609601 public static void UpdateChecksum ( Span < byte > data )
610602 => ChecksumCalculator . Update ( data ) ;
611-
612- /// <summary>
613- /// Updates the checksum in the provided data buffer.
614- /// </summary>
615- public static void UpdateChecksum ( byte [ ] data )
616- => ChecksumCalculator . Update ( data . AsSpan ( ) ) ;
617603}
618604
619605/// <summary>
@@ -665,22 +651,45 @@ public static ref D2SaveLayoutV104 From(Span<byte> data)
665651 return ref layout ;
666652 }
667653
668- /// <summary>
669- /// Gets a reference to the layout from a byte array.
670- /// Throws InvalidDataException if magic values are invalid or version is < 104.
671- /// </summary>
672- public static ref D2SaveLayoutV104 From ( byte [ ] data )
673- => ref From ( data . AsSpan ( ) ) ;
674-
675654 /// <summary>
676655 /// Updates the checksum in the provided data buffer.
677656 /// </summary>
678657 public static void UpdateChecksum ( Span < byte > data )
679658 => ChecksumCalculator . Update ( data ) ;
659+ }
660+
661+ /// <summary>
662+ /// Blittable layout for the fixed 64-byte header of a shared stash tab.
663+ /// Provides zero-copy access to tab header fields without parsing items.
664+ /// </summary>
665+ [ StructLayout ( LayoutKind . Explicit , Size = Size ) ]
666+ public unsafe struct D2StashTabLayout
667+ {
668+ /// <summary>Size of the stash tab header in bytes.</summary>
669+ public const int Size = 64 ;
670+
671+ [ FieldOffset ( 0 ) ] public uint Magic ;
672+ [ FieldOffset ( 4 ) ] public uint StashFormat ;
673+ [ FieldOffset ( 8 ) ] public uint ItemFormat ;
674+ [ FieldOffset ( 12 ) ] public uint Gold ;
675+ [ FieldOffset ( 16 ) ] public ushort TabSize ;
676+ [ FieldOffset ( 18 ) ] public ushort Season ;
677+ [ FieldOffset ( 20 ) ] public StashTabType TabType ;
678+ [ FieldOffset ( 21 ) ] private fixed byte _reserved [ 43 ] ;
679+
680+ private readonly bool IsValid => Magic == D2StashTab . Magic ;
680681
681682 /// <summary>
682- /// Updates the checksum in the provided data buffer .
683+ /// Gets a reference to the layout from a byte span at the given offset .
683684 /// </summary>
684- public static void UpdateChecksum ( byte [ ] data )
685- => ChecksumCalculator . Update ( data . AsSpan ( ) ) ;
685+ public static ref D2StashTabLayout From ( Span < byte > data , int offset = 0 )
686+ {
687+ if ( data . Length - offset < Size )
688+ throw new InvalidDataException ( $ "Data too small for stash tab header: { data . Length - offset } bytes, need { Size } .") ;
689+ ref var layout = ref MemoryMarshal . AsRef < D2StashTabLayout > ( data [ offset ..] ) ;
690+ if ( ! layout . IsValid )
691+ throw new InvalidDataException ( $ "Invalid stash tab magic: 0x{ layout . Magic : X8} , expected 0x{ D2StashTab . Magic : X8} ") ;
692+ return ref layout ;
693+ }
694+
686695}
0 commit comments