diff --git a/LibHac/HierarchicalIntegrityVerificationStream.cs b/LibHac/HierarchicalIntegrityVerificationStream.cs index c6b2d9d5..dfdb3f2c 100644 --- a/LibHac/HierarchicalIntegrityVerificationStream.cs +++ b/LibHac/HierarchicalIntegrityVerificationStream.cs @@ -82,7 +82,7 @@ namespace LibHac public override void Flush() { - throw new NotImplementedException(); + DataLevel.Flush(); } public override long Seek(long offset, SeekOrigin origin) @@ -115,7 +115,7 @@ namespace LibHac public override void Write(byte[] buffer, int offset, int count) { - throw new NotImplementedException(); + DataLevel.Write(buffer, offset, count); } public override bool CanRead => DataLevel.CanRead; diff --git a/LibHac/IntegrityVerificationStream.cs b/LibHac/IntegrityVerificationStream.cs index 4c07f700..397a2c4b 100644 --- a/LibHac/IntegrityVerificationStream.cs +++ b/LibHac/IntegrityVerificationStream.cs @@ -30,11 +30,6 @@ namespace LibHac BlockValidities = new Validity[SectorCount]; } - public override void Flush() - { - throw new NotImplementedException(); - } - public override long Seek(long offset, SeekOrigin origin) { switch (origin) @@ -119,6 +114,11 @@ namespace LibHac int toWrite = (int)Math.Min(count, Length - Position); byte[] hash = DoHash(buffer, offset, toWrite); + if (Type == IntegrityStreamType.Save && buffer.IsEmpty()) + { + Array.Clear(hash, 0, DigestSize); + } + base.Write(buffer, offset, count); HashStream.Position = blockNum * DigestSize; @@ -148,6 +148,12 @@ namespace LibHac return hash; } + public override void Flush() + { + HashStream.Flush(); + base.Flush(); + } + public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; diff --git a/LibHac/Save/AllocationTableStream.cs b/LibHac/Save/AllocationTableStream.cs index 9adb6884..e7acf015 100644 --- a/LibHac/Save/AllocationTableStream.cs +++ b/LibHac/Save/AllocationTableStream.cs @@ -22,7 +22,7 @@ namespace LibHac.Save public override void Flush() { - throw new NotImplementedException(); + Data.Flush(); } public override int Read(byte[] buffer, int offset, int count) @@ -125,5 +125,11 @@ namespace LibHac.Save Data.Position = Iterator.PhysicalBlock * BlockSize + segmentPos; } } + + protected override void Dispose(bool disposing) + { + Flush(); + base.Dispose(disposing); + } } } diff --git a/LibHac/Save/DuplexFs.cs b/LibHac/Save/DuplexFs.cs index 86282822..7e266f90 100644 --- a/LibHac/Save/DuplexFs.cs +++ b/LibHac/Save/DuplexFs.cs @@ -28,7 +28,9 @@ namespace LibHac.Save public override void Flush() { - throw new NotImplementedException(); + BitmapStream?.Flush(); + DataA?.Flush(); + DataB?.Flush(); } public override int Read(byte[] buffer, int offset, int count) @@ -57,6 +59,30 @@ namespace LibHac.Save return totalBytesRead; } + public override void Write(byte[] buffer, int offset, int count) + { + long remaining = Math.Min(count, Length - Position); + if (remaining <= 0) return; + + int inOffset = offset; + + while (remaining > 0) + { + int blockNum = (int)(Position / BlockSize); + int blockPos = (int)(Position % BlockSize); + int bytesToWrite = (int)Math.Min(remaining, BlockSize - blockPos); + + Stream data = Bitmap.Bitmap[blockNum] ? DataB : DataA; + data.Position = blockNum * BlockSize + blockPos; + + data.Write(buffer, inOffset, bytesToWrite); + + inOffset += bytesToWrite; + remaining -= bytesToWrite; + Position += bytesToWrite; + } + } + public override long Seek(long offset, SeekOrigin origin) { switch (origin) @@ -80,11 +106,6 @@ namespace LibHac.Save throw new NotImplementedException(); } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } - public override bool CanRead => true; public override bool CanSeek => true; public override bool CanWrite => false; diff --git a/LibHac/Save/Journal.cs b/LibHac/Save/Journal.cs index 23c8dea3..ed942cea 100644 --- a/LibHac/Save/Journal.cs +++ b/LibHac/Save/Journal.cs @@ -45,6 +45,25 @@ namespace LibHac.Save return count; } + public override void Write(byte[] buffer, int offset, int count) + { + long remaining = Math.Min(Length - Position, count); + if (remaining <= 0) return; + + int inPos = offset; + + while (remaining > 0) + { + long remainInEntry = BlockSize - Position % BlockSize; + int toRead = (int)Math.Min(remaining, remainInEntry); + BaseStream.Write(buffer, inPos, toRead); + + inPos += toRead; + remaining -= toRead; + Position += toRead; + } + } + public override long Seek(long offset, SeekOrigin origin) { switch (origin) @@ -64,11 +83,15 @@ namespace LibHac.Save } public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); - public override void Flush() => throw new NotSupportedException(); + + public override void Flush() + { + BaseStream.Flush(); + } + public override bool CanRead => true; public override bool CanSeek => true; - public override bool CanWrite => false; + public override bool CanWrite => true; public override long Length { get; } public override long Position { diff --git a/LibHac/Save/LayeredDuplexFs.cs b/LibHac/Save/LayeredDuplexFs.cs index 7042eb0f..795c743b 100644 --- a/LibHac/Save/LayeredDuplexFs.cs +++ b/LibHac/Save/LayeredDuplexFs.cs @@ -32,7 +32,7 @@ namespace LibHac.Save public override void Flush() { - throw new System.NotImplementedException(); + DataLayer.Flush(); } public override int Read(byte[] buffer, int offset, int count) @@ -52,7 +52,7 @@ namespace LibHac.Save public override void Write(byte[] buffer, int offset, int count) { - throw new System.NotImplementedException(); + DataLayer.Write(buffer, offset, count); } public override bool CanRead => DataLayer.CanRead; diff --git a/LibHac/Save/RemapStream.cs b/LibHac/Save/RemapStream.cs index d74b12ec..9486dde6 100644 --- a/LibHac/Save/RemapStream.cs +++ b/LibHac/Save/RemapStream.cs @@ -43,6 +43,27 @@ namespace LibHac.Save return count; } + public override void Write(byte[] buffer, int offset, int count) + { + if (CurrentEntry == null) throw new EndOfStreamException(); + + long remaining = Math.Min(CurrentEntry.VirtualOffsetEnd - Position, count); + if (remaining <= 0) return; + + int inPos = offset; + + while (remaining > 0) + { + long remainInEntry = CurrentEntry.VirtualOffsetEnd - Position; + int toWrite = (int)Math.Min(remaining, remainInEntry); + BaseStream.Write(buffer, inPos, toWrite); + + inPos += toWrite; + remaining -= toWrite; + Position += toWrite; + } + } + public override long Seek(long offset, SeekOrigin origin) { switch (origin) @@ -66,14 +87,9 @@ namespace LibHac.Save throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - public override void Flush() { - throw new NotImplementedException(); + BaseStream.Flush(); } private MapEntry GetMapEntry(long offset) diff --git a/LibHac/Streams/RandomAccessSectorStream.cs b/LibHac/Streams/RandomAccessSectorStream.cs index dc56f5ce..98b31804 100644 --- a/LibHac/Streams/RandomAccessSectorStream.cs +++ b/LibHac/Streams/RandomAccessSectorStream.cs @@ -46,6 +46,7 @@ namespace LibHac.Streams _baseStream.Position = _currentSector * _bufferSize; _baseStream.Write(_buffer, 0, _bufferSize); + _bufferPos = 0; _readBytes = 0; _bufferDirty = false; } @@ -53,6 +54,7 @@ namespace LibHac.Streams public override void Flush() { WriteSectorIfDirty(); + _baseStream.Flush(); } public override int Read(byte[] buffer, int offset, int count) diff --git a/LibHac/Streams/SharedStreamSource.cs b/LibHac/Streams/SharedStreamSource.cs index 471669e6..49055161 100644 --- a/LibHac/Streams/SharedStreamSource.cs +++ b/LibHac/Streams/SharedStreamSource.cs @@ -32,7 +32,13 @@ namespace LibHac.Streams return new SharedStream(this, offset, length); } - public void Flush() => BaseStream.Flush(); + public void Flush() + { + lock (Locker) + { + BaseStream.Flush(); + } + } public int Read(long readOffset, byte[] buffer, int bufferOffset, int count) { diff --git a/LibHac/Streams/SubStream.cs b/LibHac/Streams/SubStream.cs index a4c03ad3..fb77e244 100644 --- a/LibHac/Streams/SubStream.cs +++ b/LibHac/Streams/SubStream.cs @@ -21,7 +21,7 @@ namespace LibHac.Streams baseStream.Seek(offset, SeekOrigin.Begin); } - public SubStream(Stream baseStream, long offset) + public SubStream(Stream baseStream, long offset) : this(baseStream, offset, baseStream.Length - offset) { } public override int Read(byte[] buffer, int offset, int count) @@ -32,6 +32,14 @@ namespace LibHac.Streams return BaseStream.Read(buffer, offset, count); } + public override void Write(byte[] buffer, int offset, int count) + { + long remaining = Math.Min(Length - Position, count); + if (remaining <= 0) return; + + BaseStream.Write(buffer, offset, (int)remaining); + } + public override long Length { get; } public override bool CanRead => BaseStream.CanRead; public override bool CanWrite => BaseStream.CanWrite; @@ -70,10 +78,5 @@ namespace LibHac.Streams public override void SetLength(long value) => throw new NotSupportedException(); public override void Flush() => BaseStream.Flush(); - - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotImplementedException(); - } } } diff --git a/hactoolnet/ProcessSave.cs b/hactoolnet/ProcessSave.cs index 12b9a931..3d5743ce 100644 --- a/hactoolnet/ProcessSave.cs +++ b/hactoolnet/ProcessSave.cs @@ -90,7 +90,7 @@ namespace hactoolnet sb.AppendLine(); sb.AppendLine("Savefile:"); - PrintItem(sb, colLen, "CMAC Signature:", save.Header.Cmac); + PrintItem(sb, colLen, $"CMAC Signature{save.Header.SignatureValidity.GetValidityString()}:", save.Header.Cmac); PrintItem(sb, colLen, "Title ID:", $"{save.Header.ExtraData.TitleId:x16}"); PrintItem(sb, colLen, "User ID:", save.Header.ExtraData.UserId); PrintItem(sb, colLen, "Save ID:", $"{save.Header.ExtraData.SaveId:x16}");