/// <summary>Try to read everything up to the given <paramref name="delimiter"/>, ignoring delimiters that are /// preceded by <paramref name="delimiterEscape"/>.</summary> /// <param name="span">The read data, if any.</param> /// <param name="delimiter">The delimiter to look for.</param> /// <param name="delimiterEscape">If found prior to <paramref name="delimiter"/> it will skip that occurrence.</param> /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param> /// <returns>True if the <paramref name="delimiter"/> was found.</returns> public bool TryReadTo(out ReadOnlySpan <byte> span, byte delimiter, byte delimiterEscape, bool advancePastDelimiter = true) { ReadOnlySpan <byte> remaining = UnreadSpan; #if NET int index = remaining.IndexOf(delimiter); #else int index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length); #endif if ((index > 0 && remaining[index - 1] != delimiterEscape) || 0u >= (uint)index) { span = remaining.Slice(0, index); AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0)); return(true); } // This delimiter might be skipped, go down the slow path return(TryReadToSlow(out span, delimiter, delimiterEscape, index, advancePastDelimiter)); }
public static void WriteMachineEndian <T>(Span <byte> buffer, ref T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, typeof(T))); } #endif if ((uint)Unsafe.SizeOf <T>() > (uint)buffer.Length) { throw new ArgumentOutOfRangeException(); } Unsafe.WriteUnaligned <T>(ref buffer.DangerousGetPinnableReference(), value); }
public void TestAllignmentMatchLastIndexOf_Byte() { byte[] array = new byte[4 * Vector <byte> .Count]; for (int i = 0; i < array.Length; i++) { array[i] = 5; } for (var i = 0; i < Vector <byte> .Count; i++) { var span = new Span <byte>(array, i, 3 * Vector <byte> .Count); //int idx = span.LastIndexOf<byte>(5); int idx = SpanHelpers.FindLastIndex(ref MemoryMarshal.GetReference(span), x => x == 5, span.Length); Assert.Equal(span.Length - 1, idx); span = new Span <byte>(array, i, 3 * Vector <byte> .Count - 3); //idx = span.LastIndexOf<byte>(5); idx = SpanHelpers.FindLastIndex(ref MemoryMarshal.GetReference(span), x => x == 5, span.Length); Assert.Equal(span.Length - 1, idx); } }
/// <summary>Try to read everything up to the given <paramref name="delimiter"/>.</summary> /// <param name="span">The read data, if any.</param> /// <param name="delimiter">The delimiter to look for.</param> /// <param name="advancePastDelimiter">True to move past the <paramref name="delimiter"/> if found.</param> /// <returns>True if the <paramref name="delimiter"/> was found.</returns> public bool TryReadTo(out ReadOnlySpan <byte> span, byte delimiter, bool advancePastDelimiter = true) { ReadOnlySpan <byte> remaining = UnreadSpan; #if NET int index = remaining.IndexOf(delimiter); #else int index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length); #endif uint uIndex = (uint)index; if (SharedConstants.TooBigOrNegative >= uIndex) // index != -1 { span = 0u >= uIndex ? default : remaining.Slice(0, index); AdvanceCurrentSpan(index + (advancePastDelimiter ? 1 : 0)); return(true); } return(TryReadToSlow(out span, delimiter, advancePastDelimiter)); }
public static void WriteMachineEndian <T>(Span <byte> buffer, ref T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #endif if ((uint)Unsafe.SizeOf <T>() > (uint)buffer.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } Unsafe.WriteUnaligned <T>(ref MemoryMarshal.GetReference(buffer), value); }
public int ForEachByte(int index, int count, IByteProcessor visitor) { var thisLength = this.length; if (0u >= (uint)thisLength) { return(IndexNotFound); } if (MathUtil.IsOutOfBounds(index, count, thisLength)) { ThrowIndexOutOfRangeException_Index(index, count, thisLength); } var idx = SpanHelpers.ForEachByte(ref this.value[this.offset + index], visitor, count); if ((uint)count > (uint)idx) { return(index + idx); } return(IndexNotFound); }
public void TestNoMatch_Byte() { var rnd = new Random(42); for (int length = 0; length <= byte.MaxValue; length++) { byte[] a = new byte[length]; byte target = (byte)rnd.Next(0, 256); for (int i = 0; i < length; i++) { byte val = (byte)(i + 1); a[i] = val == target ? (byte)(target + 1) : val; } Span <byte> span = new Span <byte>(a); //int idx = span.IndexOf(target); int idx = SpanHelpers.FindIndex(ref MemoryMarshal.GetReference(span), x => x == target, span.Length); Assert.Equal(-1, idx); } }
public static T ReadMachineEndian <T>(ReadOnlySpan <byte> buffer) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #endif if (Unsafe.SizeOf <T>() > buffer.Length) { ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.length); } return(Unsafe.ReadUnaligned <T>(ref buffer.DangerousGetPinnableReference())); }
public void TestMatch_Byte() { for (int length = 0; length <= byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) { a[i] = (byte)(i + 1); } Span <byte> span = new Span <byte>(a); for (int targetIndex = 0; targetIndex < length; targetIndex++) { byte target = a[targetIndex]; //int idx = span.IndexOf(target); int idx = SpanHelpers.FindIndex(ref MemoryMarshal.GetReference(span), x => x == target, span.Length); Assert.Equal(targetIndex, idx); } } }
public void TestMultipleMatchLastIndexOf_Byte() { for (int length = 2; length <= byte.MaxValue; length++) { byte[] a = new byte[length]; for (int i = 0; i < length; i++) { byte val = (byte)(i + 1); a[i] = val == 200 ? (byte)201 : val; } a[length - 1] = 200; a[length - 2] = 200; Span <byte> span = new Span <byte>(a); //int idx = span.LastIndexOf<byte>(200); int idx = SpanHelpers.FindLastIndex(ref MemoryMarshal.GetReference(span), x => x == 200, span.Length); Assert.Equal(length - 1, idx); } }
public static bool TryWriteMachineEndian <T>(Span <byte> buffer, ref T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #endif if (Unsafe.SizeOf <T>() > (uint)buffer.Length) { return(false); } Unsafe.WriteUnaligned <T>(ref buffer.DangerousGetPinnableReference(), value); return(true); }
private static string Print(this AesXtsFile xtsFile, int contentType) { int colLen = 36; var sb = new StringBuilder(); sb.AppendLine(); sb.AppendLine("NAX0:"); AesXtsFileHeader header = xtsFile.Header; uint magic = header.Magic; PrintItem(sb, colLen, " Magic:", Util.GetUtf8String(SpanHelpers.AsReadOnlyByteSpan(ref magic))); PrintItem(sb, colLen, " Content Type:", GetContentType(contentType)); PrintItem(sb, colLen, " Content Size:", $"{header.Size:x12}"); PrintItem(sb, colLen, " Header HMAC:", header.Signature); PrintItem(sb, colLen, " Encrypted Keys:", header.EncryptedKey1.Concat(header.EncryptedKey2).ToArray()); PrintItem(sb, colLen, " Decrypted Keys:", header.DecryptedKey1.Concat(header.DecryptedKey2).ToArray()); return(sb.ToString()); }
public static bool TryWriteMachineEndian <T>(Span <byte> destination, ref T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #endif if (Unsafe.SizeOf <T>() > (uint)destination.Length) { return(false); } Unsafe.WriteUnaligned <T>(ref MemoryMarshal.GetReference(destination), value); return(true); }
private bool TryReadToInternal(out ReadOnlySequence <byte> sequence, byte delimiter, bool advancePastDelimiter, int skip = 0) { Debug.Assert(skip >= 0); ByteBufferReader copy = this; if (skip > 0) { Advance(skip); } ReadOnlySpan <byte> remaining = UnreadSpan; while (_moreData) { int index = SpanHelpers.IndexOf(ref MemoryMarshal.GetReference(remaining), delimiter, remaining.Length); uint uIndex = (uint)index; if (SharedConstants.TooBigOrNegative >= uIndex) // index != -1 { // Found the delimiter. Move to it, slice, then move past it. if (uIndex > 0u) // 此时 index 为非负值 { AdvanceCurrentSpan(index); } sequence = _sequence.Slice(copy.Position, Position); if (advancePastDelimiter) { Advance(1); } return(true); } AdvanceCurrentSpan(remaining.Length); remaining = _currentSpan; } // Didn't find anything, reset our original state. this = copy; sequence = default; return(false); }
private void AddUpdate(string path) { if (File.Exists(path)) { using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read)) { PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); try { (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0); if (controlNca != null && patchNca != null) { ApplicationControlProperty controlData = new ApplicationControlProperty(); controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(out IFile nacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); nacpFile.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}"); radioButton.JoinGroup(_noUpdateRadioButton); _availableUpdatesBox.Add(radioButton); _radioButtonToPathDictionary.Add(radioButton, path); radioButton.Show(); radioButton.Active = true; } else { GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!"); } } catch (Exception exception) { GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}"); } } } }
public static bool TryReadMachineEndian <T>(ReadOnlySpan <byte> source, out T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #endif if (Unsafe.SizeOf <T>() > (uint)source.Length) { value = default; return(false); } value = Unsafe.ReadUnaligned <T>(ref MemoryMarshal.GetReference(source)); return(true); }
public bool ContentEquals(ICharSequence other) { if (ReferenceEquals(this, other)) { return(true); } var thisLength = this.length; if (other is null || thisLength != other.Count) { return(false); } switch (other) { case AsciiString asciiStr: return(this.GetHashCode() == asciiStr.GetHashCode() #if NET && this.AsciiSpan.SequenceEqual(asciiStr.AsciiSpan)); #else && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(this.AsciiSpan), ref MemoryMarshal.GetReference(asciiStr.AsciiSpan), thisLength);
public int LastIndexOf(ICharSequence subString, int start) { int thisLen = this.length; uint uThisLen = (uint)thisLen; if (0u >= uThisLen) { return(IndexNotFound); } int subCount = subString.Count; start = Math.Min(start, thisLen - subCount); uint uStart = (uint)start; if (uStart > SharedConstants.TooBigOrNegative) { return(IndexNotFound); } if (0u >= (uint)subCount) { return(start); } if (subString is IHasAsciiSpan hasAscii) { return(SpanHelpers.LastIndexOf( ref MemoryMarshal.GetReference(this.AsciiSpan), start + subCount, ref MemoryMarshal.GetReference(hasAscii.AsciiSpan), subCount)); } if (subString is IHasUtf16Span hasUtf16) { return(SpanHelpers.LastIndexOf( ref MemoryMarshal.GetReference(this.Utf16Span), start + subCount, ref MemoryMarshal.GetReference(hasUtf16.Utf16Span), subCount)); } return(LastIndexOf0(subString, start)); }
public static bool TryReadMachineEndian <T>(ReadOnlySpan <byte> buffer, out T value) where T : struct { #if netstandard if (SpanHelpers.IsReferenceOrContainsReferences <T>()) { ThrowHelper.ThrowArgumentException_InvalidTypeWithPointersNotSupported(typeof(T)); } #else if (RuntimeHelpers.IsReferenceOrContainsReferences <T>()) { throw new ArgumentException(SR.Format(SR.Argument_InvalidTypeWithPointersNotSupported, typeof(T))); } #endif if (Unsafe.SizeOf <T>() > (uint)buffer.Length) { value = default; return(false); } value = Unsafe.ReadUnaligned <T>(ref buffer.DangerousGetPinnableReference()); return(true); }
public Result ReadKeyValue(Span <byte> keyBuffer, Span <byte> valueBuffer) { // This should only be called after ReadEntryCount. Assert.SdkNotEqual(_offset, 0); // Read the next entry header. Unsafe.SkipInit(out KeyValueArchiveEntryHeader header); Result rc = Read(SpanHelpers.AsByteSpan(ref header)); if (rc.IsFailure()) { return(rc); } if (!header.IsValid()) { return(ResultKvdb.InvalidKeyValue.Log()); } // Key size and Value size must be correct. Assert.SdkEqual(keyBuffer.Length, header.KeySize); Assert.SdkEqual(valueBuffer.Length, header.ValueSize); rc = Read(keyBuffer); if (rc.IsFailure()) { return(rc); } rc = Read(valueBuffer); if (rc.IsFailure()) { return(rc); } return(Result.Success); }
public Result GetEntryCount(out long entryCount) { entryCount = 0; long count = 0; Result rc = BaseFileSystem.OpenDirectory(out IDirectory _, Path, OpenDirectoryMode.All | OpenDirectoryMode.NoFileSize); if (rc.IsFailure()) { return(rc); } var entry = new DirectoryEntry(); Span <DirectoryEntry> entrySpan = SpanHelpers.AsSpan(ref entry); while (true) { rc = ParentDirectory.Read(out long baseEntriesRead, entrySpan); if (rc.IsFailure()) { return(rc); } if (baseEntriesRead == 0) { break; } if (CanReturnEntry(entry, IsConcatenationFile(entry))) { count++; } } entryCount = count; return(Result.Success); }
public static bool Contains(this ICharSequence sequence, char c) { switch (sequence) { case null: return(false); case IHasAsciiSpan hasAscii: if ((uint)c > AsciiString.uMaxCharValue) { return(false); } #if NET return(hasAscii.AsciiSpan.Contains((byte)c)); #else var asciiSpan = hasAscii.AsciiSpan; return(SpanHelpers.Contains(ref MemoryMarshal.GetReference(asciiSpan), (byte)c, asciiSpan.Length)); #endif case IHasUtf16Span hasUtf16: #if NET #else var utf16Span = hasUtf16.Utf16Span; return(SpanHelpers.Contains(ref MemoryMarshal.GetReference(utf16Span), c, utf16Span.Length)); #endif default: int length = sequence.Count; for (int i = 0; i < length; i++) { if (sequence[i] == c) { return(true); } } return(false); } }
public override bool Equals(object obj) { if (ReferenceEquals(this, obj)) { return(true); } switch (obj) { case AppendableCharSequence other: return(_pos == other._pos && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(AsciiSpan), ref MemoryMarshal.GetReference(other.AsciiSpan), _pos)); case IHasAsciiSpan hasAscii: return(AsciiSpan.SequenceEqual(hasAscii.AsciiSpan)); case ICharSequence seq: return(ContentEquals(seq)); default: return(false); } }
bool IEquatable <ICharSequence> .Equals(ICharSequence other) { if (ReferenceEquals(this, other)) { return(true); } switch (other) { case null: return(false); case AppendableCharSequence comparand: return(_pos == comparand._pos && SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(AsciiSpan), ref MemoryMarshal.GetReference(comparand.AsciiSpan), _pos)); case IHasAsciiSpan hasAscii: return(AsciiSpan.SequenceEqual(hasAscii.AsciiSpan)); default: return(false); } }
/// <summary> /// Returns <c>true</c> if and only if the two specified buffers are /// identical to each other for {@code length} bytes starting at {@code aStartIndex} /// index for the {@code a} buffer and {@code bStartIndex} index for the {@code b} buffer. /// A more compact way to express this is: /// <p /> /// {@code a[aStartIndex : aStartIndex + length] == b[bStartIndex : bStartIndex + length]} /// </summary> public static bool Equals(IByteBuffer a, int aStartIndex, IByteBuffer b, int bStartIndex, int length) { if (aStartIndex < 0 || bStartIndex < 0 || length < 0) { ThrowHelper.ThrowArgumentException_NonNegative(); } if (a.WriterIndex - length < aStartIndex || b.WriterIndex - length < bStartIndex) { return(false); } if (a.IsSingleIoBuffer && b.IsSingleIoBuffer) { var spanA = a.GetReadableSpan(aStartIndex, length); var spanB = b.GetReadableSpan(bStartIndex, length); #if NET return(spanA.SequenceEqual(spanB)); #else return(SpanHelpers.SequenceEqual(ref MemoryMarshal.GetReference(spanA), ref MemoryMarshal.GetReference(spanB), length)); #endif } return(EqualsSlow(a, aStartIndex, b, bStartIndex, length)); }
protected override Result DoGetEntryCount(out long entryCount) { entryCount = 0; long totalEntryCount = 0; var entry = new DirectoryEntry(); // todo: Efficient way to remove duplicates var names = new HashSet <string>(); // Open new directories for each source because we need to remove duplicate entries foreach (IFileSystem fs in SourceFileSystems) { Result rc = fs.OpenDirectory(out IDirectory dir, Path, Mode); if (rc.IsFailure()) { return(rc); } long entriesRead; do { rc = dir.Read(out entriesRead, SpanHelpers.AsSpan(ref entry)); if (rc.IsFailure()) { return(rc); } if (entriesRead == 1 && names.Add(StringUtils.Utf8ZToString(entry.Name))) { totalEntryCount++; } } while (entriesRead != 0); } entryCount = totalEntryCount; return(Result.Success); }
public IStorage OpenRawStorageWithPatch(Nca patchNca, int index) { IStorage patchStorage = patchNca.OpenRawStorage(index); IStorage baseStorage = SectionExists(index) ? OpenRawStorage(index) : new NullStorage(); patchStorage.GetSize(out long patchSize).ThrowIfFailure(); baseStorage.GetSize(out long baseSize).ThrowIfFailure(); NcaFsHeader header = patchNca.Header.GetFsHeader(index); NcaFsPatchInfo patchInfo = header.GetPatchInfo(); if (patchInfo.RelocationTreeSize == 0) { return(patchStorage); } var treeHeader = new BucketTree.Header(); patchInfo.RelocationTreeHeader.CopyTo(SpanHelpers.AsByteSpan(ref treeHeader)); long nodeStorageSize = IndirectStorage.QueryNodeStorageSize(treeHeader.EntryCount); long entryStorageSize = IndirectStorage.QueryEntryStorageSize(treeHeader.EntryCount); var relocationTableStorage = new SubStorage(patchStorage, patchInfo.RelocationTreeOffset, patchInfo.RelocationTreeSize); var cachedTableStorage = new CachedStorage(relocationTableStorage, IndirectStorage.NodeSize, 4, true); var tableNodeStorage = new SubStorage(cachedTableStorage, 0, nodeStorageSize); var tableEntryStorage = new SubStorage(cachedTableStorage, nodeStorageSize, entryStorageSize); var storage = new IndirectStorage(); storage.Initialize(tableNodeStorage, tableEntryStorage, treeHeader.EntryCount).ThrowIfFailure(); storage.SetStorage(0, baseStorage, 0, baseSize); storage.SetStorage(1, patchStorage, 0, patchSize); return(storage); }
public Result Read(out long readCount, Span <byte> saveDataInfoBuffer) { readCount = default; Span <SaveDataInfo> outInfo = MemoryMarshal.Cast <byte, SaveDataInfo>(saveDataInfoBuffer); SaveDataInfo tempInfo = default; Span <byte> tempInfoBytes = SpanHelpers.AsByteSpan(ref tempInfo); ISaveDataInfoReader reader = Reader.Target; int count = 0; while (count < outInfo.Length) { Result rc = reader.Read(out long baseReadCount, tempInfoBytes); if (rc.IsFailure()) { return(rc); } if (baseReadCount == 0) { break; } if (Filter.Matches(ref tempInfo)) { outInfo[count] = tempInfo; count++; } } readCount = count; return(Result.Success); }
/// <summary> /// Adds a new entry to the bucket tree. /// </summary> /// <typeparam name="T">The type of the entry to add. Added entries should all be the same type.</typeparam> /// <param name="entry">The entry to add.</param> /// <returns>The <see cref="Result"/> of the operation.</returns> public Result Add <T>(ref T entry) where T : unmanaged { Assert.True(Unsafe.SizeOf <T>() == EntrySize); if (CurrentEntryIndex >= EntryCount) { return(ResultFs.OutOfRange.Log()); } // The entry offset must always be the first 8 bytes of the struct long entryOffset = BinaryPrimitives.ReadInt64LittleEndian(SpanHelpers.AsByteSpan(ref entry)); if (entryOffset <= CurrentOffset) { return(ResultFs.InvalidOffset.Log()); } Result rc = FinalizePreviousEntrySet(entryOffset); if (rc.IsFailure()) { return(rc); } AddEntryOffset(entryOffset); // Write the new entry int indexInEntrySet = CurrentEntryIndex % EntriesPerEntrySet; _entrySet.GetNode <T>().GetWritableArray()[indexInEntrySet] = entry; CurrentOffset = entryOffset; CurrentEntryIndex++; return(Result.Success); }
private IStorage OpenAesCtrExStorage(IStorage baseStorage, int index) { NcaFsHeader fsHeader = Header.GetFsHeader(index); NcaFsPatchInfo info = fsHeader.GetPatchInfo(); long sectionOffset = Header.GetSectionStartOffset(index); long sectionSize = Header.GetSectionSize(index); long bktrOffset = info.RelocationTreeOffset; long bktrSize = sectionSize - bktrOffset; long dataSize = info.RelocationTreeOffset; byte[] key = GetContentKey(NcaKeyType.AesCtr); byte[] counter = Aes128CtrStorage.CreateCounter(fsHeader.Counter, bktrOffset + sectionOffset); byte[] counterEx = Aes128CtrStorage.CreateCounter(fsHeader.Counter, sectionOffset); IStorage bucketTreeData = new CachedStorage(new Aes128CtrStorage(baseStorage.Slice(bktrOffset, bktrSize), key, counter, true), 4, true); var encryptionBucketTreeData = new SubStorage(bucketTreeData, info.EncryptionTreeOffset - bktrOffset, sectionSize - info.EncryptionTreeOffset); var cachedBucketTreeData = new CachedStorage(encryptionBucketTreeData, IndirectStorage.NodeSize, 6, true); var treeHeader = new BucketTree.Header(); info.EncryptionTreeHeader.CopyTo(SpanHelpers.AsByteSpan(ref treeHeader)); long nodeStorageSize = IndirectStorage.QueryNodeStorageSize(treeHeader.EntryCount); long entryStorageSize = IndirectStorage.QueryEntryStorageSize(treeHeader.EntryCount); var tableNodeStorage = new SubStorage(cachedBucketTreeData, 0, nodeStorageSize); var tableEntryStorage = new SubStorage(cachedBucketTreeData, nodeStorageSize, entryStorageSize); IStorage decStorage = new Aes128CtrExStorage(baseStorage.Slice(0, dataSize), tableNodeStorage, tableEntryStorage, treeHeader.EntryCount, key, counterEx, true); return(new ConcatenationStorage(new[] { decStorage, bucketTreeData }, true)); }