diff --git a/.editorconfig b/.editorconfig index 6a23442..e187e44 100644 --- a/.editorconfig +++ b/.editorconfig @@ -120,7 +120,7 @@ csharp_style_prefer_pattern_matching = true csharp_style_prefer_switch_expression = true # Null-checking preferences -csharp_style_conditional_delegate_call = true +csharp_style_conditional_delegate_call = true:suggestion # Modifier preferences csharp_prefer_static_anonymous_function = true @@ -188,7 +188,7 @@ csharp_space_after_comma = true csharp_space_after_dot = false csharp_space_after_keywords_in_control_flow_statements = true csharp_space_after_semicolon_in_for_statement = true -csharp_space_around_binary_operators = ignore +csharp_space_around_binary_operators = before_and_after csharp_space_around_declaration_statements = false csharp_space_before_colon_in_inheritance_clause = true csharp_space_before_comma = false diff --git a/sources/OpenMcdf/CompoundFile.cs b/sources/OpenMcdf/CompoundFile.cs index 7f3f034..60d6966 100644 --- a/sources/OpenMcdf/CompoundFile.cs +++ b/sources/OpenMcdf/CompoundFile.cs @@ -727,6 +727,8 @@ List miniStream null, sourceStream); + + // Set updated/new sectors within the ministream // We are writing data in a NORMAL Sector chain. for (int i = 0; i < sectorChain.Count; i++) @@ -743,9 +745,13 @@ List miniStream s.Id = (int)(miniStreamView.Position - Sector.MINISECTOR_SIZE) / Sector.MINISECTOR_SIZE; RootStorage.DirEntry.Size = miniStreamView.Length; + + } } + + // Update miniFAT StreamRW miniFATStreamRW = new(miniFATView); for (int i = 0; i < sectorChain.Count - 1; i++) @@ -754,12 +760,14 @@ List miniStream int nextId = sectorChain[i + 1].Id; miniFATStreamRW.Seek(currentId * 4, SeekOrigin.Begin); miniFATStreamRW.Write(nextId); + } // Write End of Chain in MiniFAT miniFATStreamRW.Seek(sectorChain[sectorChain.Count - 1].Id * SIZE_OF_SID, SeekOrigin.Begin); miniFATStreamRW.Write(Sector.ENDOFCHAIN); + // Update sector chains AllocateSectorChain(miniStreamView.BaseSectorChain); AllocateSectorChain(miniFATView.BaseSectorChain); @@ -1007,6 +1015,10 @@ private void AllocateFATSectorChain(List sectorChain) /// A FAT sector chain private void AllocateDIFATSectorChain(List FATsectorChain) { + //Get initial DIFAT chain + List difatSectors = + GetSectorChain(-1, SectorType.DIFAT); + // Get initial sector's count header.FATSectorsNumber = FATsectorChain.Count; @@ -1022,10 +1034,11 @@ private void AllocateDIFATSectorChain(List FATsectorChain) } // Sector count... - int nCurrentSectors = sectors.Count; + //int nCurrentSectors = sectors.Count; // Temp DIFAT count - int nDIFATSectors = (int)header.DIFATSectorsNumber; + //int nDIFATSectors = (int)header.DIFATSectorsNumber; + int nDIFATSectors = 0; if (FATsectorChain.Count > HEADER_DIFAT_ENTRIES_COUNT) { @@ -1033,11 +1046,22 @@ private void AllocateDIFATSectorChain(List FATsectorChain) nDIFATSectors = LowSaturation(nDIFATSectors - (int)header.DIFATSectorsNumber); //required DIFAT } + + for (int i = 0; i < (nDIFATSectors - difatSectors.Count); i++) + { + Sector s = new Sector(SectorSize, sourceStream); + sectors.Add(s); + s.Id = sectors.Count - 1; + s.Type = SectorType.DIFAT; + difatSectors.Add(s); + } + // ...sum with new required DIFAT sectors count - nCurrentSectors += nDIFATSectors; + //nCurrentSectors += nDIFATSectors; + //header.FATSectorsNumber += nDIFATSectors; // ReCheck FAT bias - while (header.FATSectorsNumber * FAT_SECTOR_ENTRIES_COUNT < nCurrentSectors) + while (FATsectorChain.Count * FAT_SECTOR_ENTRIES_COUNT < sectors.Count) { Sector extraFATSector = new Sector(SectorSize, sourceStream); sectors.Add(extraFATSector); @@ -1047,26 +1071,25 @@ private void AllocateDIFATSectorChain(List FATsectorChain) FATsectorChain.Add(extraFATSector); - header.FATSectorsNumber++; - nCurrentSectors++; + //header.FATSectorsNumber++; + //nCurrentSectors++; //... so, adding a FAT sector may induce DIFAT sectors to increase by one // and consequently this may induce ANOTHER FAT sector (TO-THINK: May this condition occur ?) - if (nDIFATSectors * DIFAT_SECTOR_FAT_ENTRIES_COUNT < - (header.FATSectorsNumber > HEADER_DIFAT_ENTRIES_COUNT ? - header.FATSectorsNumber - HEADER_DIFAT_ENTRIES_COUNT : - 0)) + if (difatSectors.Count * DIFAT_SECTOR_FAT_ENTRIES_COUNT < (FATsectorChain.Count - HEADER_DIFAT_ENTRIES_COUNT)) { - nDIFATSectors++; - nCurrentSectors++; + + Sector s = new Sector(SectorSize, sourceStream); + sectors.Add(s); + s.Type = SectorType.DIFAT; + s.Id = sectors.Count - 1; + difatSectors.Add(s); + } } - List difatSectors = - GetSectorChain(-1, SectorType.DIFAT); - using StreamView difatStream - = new StreamView(difatSectors, SectorSize, sourceStream); + = new StreamView(difatSectors, SectorSize, difatSectors.Count * SectorSize, null, sourceStream); StreamRW difatStreamRW = new(difatStream); @@ -1101,7 +1124,7 @@ private void AllocateDIFATSectorChain(List FATsectorChain) } } - header.DIFATSectorsNumber = (uint)nDIFATSectors; + header.DIFATSectorsNumber = (uint)difatStream.BaseSectorChain.Count; // Chain first sector if (difatStream.BaseSectorChain != null && difatStream.BaseSectorChain.Count > 0) @@ -1130,16 +1153,17 @@ private void AllocateDIFATSectorChain(List FATsectorChain) // Mark DIFAT Sectors in FAT using StreamView fatSv = - new StreamView(FATsectorChain, SectorSize, header.FATSectorsNumber * SectorSize, null, sourceStream); + new StreamView(FATsectorChain, SectorSize, FATsectorChain.Count * SectorSize, null, sourceStream); StreamRW streamRW = new(fatSv); - for (int i = 0; i < header.DIFATSectorsNumber; i++) + + for (int i = 0; i < difatStream.BaseSectorChain.Count; i++) { streamRW.Seek(difatStream.BaseSectorChain[i].Id * 4, SeekOrigin.Begin); streamRW.Write(Sector.DIFSECT); } - for (int i = 0; i < header.FATSectorsNumber; i++) + for (int i = 0; i < fatSv.BaseSectorChain.Count; i++) { streamRW.Seek(fatSv.BaseSectorChain[i].Id * 4, SeekOrigin.Begin); streamRW.Write(Sector.FATSECT); @@ -1148,7 +1172,8 @@ private void AllocateDIFATSectorChain(List FATsectorChain) //fatSv.Seek(fatSv.BaseSectorChain[fatSv.BaseSectorChain.Count - 1].Id * 4, SeekOrigin.Begin); //fatSv.Write(BitConverter.GetBytes(Sector.ENDOFCHAIN), 0, 4); - header.FATSectorsNumber = fatSv.BaseSectorChain.Count; + header.FATSectorsNumber = FATsectorChain.Count; + header.DIFATSectorsNumber = (uint)difatSectors.Count; } /// @@ -1244,9 +1269,8 @@ List result List difatSectors = GetDifatSectorChain(); int idx = 0; - - int nextSecID; + // Read FAT entries from the header Fat entry array (max 109 entries) while (idx < header.FATSectorsNumber && idx < N_HEADER_FAT_ENTRY) { @@ -1277,9 +1301,7 @@ List result ( difatSectors, SectorSize, - header.FATSectorsNumber > N_HEADER_FAT_ENTRY ? - (header.FATSectorsNumber - N_HEADER_FAT_ENTRY) * 4 : - 0, + difatSectors.Count * SectorSize, null, sourceStream); @@ -1340,6 +1362,7 @@ List result using StreamView fatStream = new StreamView(fatSectors, SectorSize, fatSectors.Count * SectorSize, null, sourceStream); StreamRW fatStreamRW = new(fatStream); + while (true) { if (nextSecID == Sector.ENDOFCHAIN) break; @@ -1389,12 +1412,12 @@ List result List miniStream = GetNormalSectorChain(RootEntry.StartSect); using StreamView miniFATView - = new StreamView(miniFAT, SectorSize, header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, null, sourceStream); + = new StreamView(miniFAT, SectorSize, header.MiniFATSectorsNumber * SectorSize, null, sourceStream); using StreamView miniStreamView = new StreamView(miniStream, SectorSize, RootStorage.Size, null, sourceStream); - using BinaryReader miniFATReader = new BinaryReader(miniFATView); + StreamRW miniFATReader = new StreamRW(miniFATView); int nextSecID = secID; HashSet processedSectors = new HashSet(); @@ -1834,7 +1857,7 @@ List miniFAT = GetSectorChain(header.FirstMiniFATSectorID, SectorType.Normal); using StreamView miniFATView - = new StreamView(miniFAT, SectorSize, header.MiniFATSectorsNumber * Sector.MINISECTOR_SIZE, null, sourceStream); + = new StreamView(miniFAT, SectorSize, header.MiniFATSectorsNumber * SectorSize, null, sourceStream); StreamRW miniFATStreamRW = new(miniFATView); diff --git a/sources/OpenMcdf/StreamView.cs b/sources/OpenMcdf/StreamView.cs index 3da6467..f7f5f54 100644 --- a/sources/OpenMcdf/StreamView.cs +++ b/sources/OpenMcdf/StreamView.cs @@ -94,6 +94,9 @@ public override int Read(byte[] buffer, int offset, int count) long intMax = Math.Min(int.MaxValue, length); count = Math.Min((int)intMax, count); + // Ensure read request greater then stream length, when position is not 0, return only the limited and correct number of bytes + count = (int)Math.Min(length - position, count); + if (BaseSectorChain != null && BaseSectorChain.Count > 0) { // First sector diff --git a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs index ae994ba..80e4618 100644 --- a/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs +++ b/sources/Test/OpenMcdf.Extensions.Test/OLEPropertiesExtensionsTest.cs @@ -472,5 +472,27 @@ public void Test_Retain_Dictionary_Property_In_AppSpecific_Streams() CollectionAssert.AreEqual(expectedPropertyNames, co.PropertyNames); } } + + [TestMethod] + public void Test_FIX_CRASH() + { + using CompoundFile cf = new(CFSVersion.Ver_4, CFSConfiguration.Default); + + CFStream cfStream = cf.RootStorage.AddStream("MyStream"); + using Stream stream = cfStream.AsIOStream(); + const int BufferLength = 4096 * 21; + var buffer = Helpers.GetBuffer(BufferLength); + stream.Write(buffer, 0, buffer.Length); + stream.Position = 0; + + Assert.AreEqual(BufferLength, cfStream.Size); + + using MemoryStream memoryStream = new(); + using BufferedStream bufferedStream = new(stream); + bufferedStream.CopyTo(memoryStream); + + Assert.AreEqual(memoryStream.Length, cfStream.Size); + + } } } diff --git a/sources/Test/OpenMcdf.Test/CompoundFileTest.cs b/sources/Test/OpenMcdf.Test/CompoundFileTest.cs index 5958f73..00e2822 100644 --- a/sources/Test/OpenMcdf.Test/CompoundFileTest.cs +++ b/sources/Test/OpenMcdf.Test/CompoundFileTest.cs @@ -1088,5 +1088,7 @@ public void Test_FIX_BUG_96_CompoundFile_SaveOverwrite() File.Delete(filename2); } + + } }