From 1db5530cb24b312064c3fc9b258251acaeb81ac4 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Sat, 10 Sep 2016 02:15:01 +0100 Subject: [PATCH] Adds support for bzip2 (UDBZ) and zlib (UDZO) compressed UDIFs. --- .../DiscImageChef.DiscImages.csproj | 3 + DiscImageChef.DiscImages/UDIF.cs | 64 +++++++++++++++++-- DiscImageChef.DiscImages/packages.config | 1 + TODO | 6 +- 4 files changed, 66 insertions(+), 8 deletions(-) diff --git a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj index 2f9366c31..50cef69b6 100644 --- a/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj +++ b/DiscImageChef.DiscImages/DiscImageChef.DiscImages.csproj @@ -34,6 +34,9 @@ ..\packages\plist-cil.1.14\lib\plist-cil.dll + + ..\packages\SharpCompress.0.12.4\lib\net40\SharpCompress.dll + diff --git a/DiscImageChef.DiscImages/UDIF.cs b/DiscImageChef.DiscImages/UDIF.cs index ac576c91e..01dcc7579 100644 --- a/DiscImageChef.DiscImages/UDIF.cs +++ b/DiscImageChef.DiscImages/UDIF.cs @@ -40,6 +40,8 @@ using DiscImageChef.CommonTypes; using DiscImageChef.Console; using DiscImageChef.ImagePlugins; using DiscImageChef.Filters; +using SharpCompress.Compressor.Deflate; +using SharpCompress.Compressor.BZip2; namespace DiscImageChef.DiscImages { @@ -146,9 +148,12 @@ namespace DiscImageChef.DiscImages Dictionary chunks; Dictionary sectorCache; + Dictionary chunkCache; const uint MaxCacheSize = 16777216; const uint sectorSize = 512; uint maxCachedSectors = MaxCacheSize / sectorSize; + uint currentChunkCacheSize; + uint buffersize; Stream imageStream; @@ -356,6 +361,7 @@ namespace DiscImageChef.DiscImages bChnk.type = ChunkType_Copy; ImageInfo.sectors = footer.sectorCount; chunks.Add(bChnk.sector, bChnk); + buffersize = 2048 * sectorSize; fakeBlockChunks = true; } @@ -411,6 +417,8 @@ namespace DiscImageChef.DiscImages if(blkxList.Count == 0) throw new ImageNotSupportedException("Could not retrieve block chunks. Please fill an issue and send it to us."); + buffersize = 0; + foreach(byte[] blkxBytes in blkxList) { BlockHeader bHdr = new BlockHeader(); @@ -437,6 +445,9 @@ namespace DiscImageChef.DiscImages DicConsole.DebugWriteLine("UDIF plugin", "bHdr.chunks = {0}", bHdr.chunks); DicConsole.DebugWriteLine("UDIF plugin", "bHdr.reservedChk is empty? = {0}", ArrayHelpers.ArrayIsNullOrEmpty(bHdr.reservedChk)); + if(bHdr.buffers > buffersize) + buffersize = bHdr.buffers * sectorSize; + for(int i = 0; i < bHdr.chunks; i++) { BlockChunk bChnk = new BlockChunk(); @@ -474,10 +485,6 @@ namespace DiscImageChef.DiscImages throw new ImageNotSupportedException("Chunks compressed with LZH are not yet supported."); if((bChnk.type == ChunkType_ADC)) throw new ImageNotSupportedException("Chunks compressed with ADC are not yet supported."); - if((bChnk.type == ChunkType_Zlib)) - throw new ImageNotSupportedException("Chunks compressed with zlib are not yet supported."); - if((bChnk.type == ChunkType_Bzip)) - throw new ImageNotSupportedException("Chunks compressed with bzip2 are not yet supported."); if((bChnk.type == ChunkType_LZFSE)) throw new ImageNotSupportedException("Chunks compressed with lzfse are not yet supported."); @@ -492,7 +499,9 @@ namespace DiscImageChef.DiscImages } sectorCache = new Dictionary(); - imageStream = stream; + chunkCache = new Dictionary(); + currentChunkCacheSize = 0; + imageStream = stream; ImageInfo.imageCreationTime = imageFilter.GetCreationTime(); ImageInfo.imageLastModificationTime = imageFilter.GetLastWriteTime(); @@ -538,6 +547,51 @@ namespace DiscImageChef.DiscImages if(!chunkFound) throw new ArgumentOutOfRangeException(nameof(sectorAddress), string.Format("Sector address {0} not found", sectorAddress)); + if((currentChunk.type & ChunkType_CompressedMask) == ChunkType_CompressedMask) + { + byte[] buffer; + if(!chunkCache.TryGetValue(chunkStartSector, out buffer)) + { + byte[] cmpBuffer = new byte[currentChunk.length]; + imageStream.Seek((long)currentChunk.offset, SeekOrigin.Begin); + imageStream.Read(cmpBuffer, 0, cmpBuffer.Length); + MemoryStream cmpMs = new MemoryStream(cmpBuffer); + Stream decStream; + + if(currentChunk.type == ChunkType_Zlib) + decStream = new ZlibStream(cmpMs, SharpCompress.Compressor.CompressionMode.Decompress); + else if(currentChunk.type == ChunkType_Bzip) + decStream = new BZip2Stream(cmpMs, SharpCompress.Compressor.CompressionMode.Decompress); + else + throw new ImageNotSupportedException(string.Format("Unsupported chunk type 0x{0:X8} found", currentChunk.type)); + + byte[] tmpBuffer = new byte[buffersize]; + int realSize = decStream.Read(tmpBuffer, 0, (int)buffersize); + buffer = new byte[realSize]; + Array.Copy(tmpBuffer, 0, buffer, 0, realSize); + tmpBuffer = null; + + if(currentChunkCacheSize + realSize > MaxCacheSize) + { + chunkCache.Clear(); + currentChunkCacheSize = 0; + } + + chunkCache.Add(chunkStartSector, buffer); + currentChunkCacheSize += (uint)realSize; + } + + sector = new byte[sectorSize]; + Array.Copy(buffer, relOff, sector, 0, sectorSize); + + if(sectorCache.Count >= maxCachedSectors) + sectorCache.Clear(); + + sectorCache.Add(sectorAddress, sector); + + return sector; + } + if(currentChunk.type == ChunkType_NoCopy || currentChunk.type == ChunkType_Zero) { sector = new byte[sectorSize]; diff --git a/DiscImageChef.DiscImages/packages.config b/DiscImageChef.DiscImages/packages.config index 2164a6948..e3e5017f5 100644 --- a/DiscImageChef.DiscImages/packages.config +++ b/DiscImageChef.DiscImages/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/TODO b/TODO index 297c0c629..a5ec4423b 100644 --- a/TODO +++ b/TODO @@ -64,13 +64,13 @@ VMDK plugin: --- Add support for encrypted extents UDIF plugin: ---- Add support for compressed chunks +--- Add support for chunks compressed with ADC, RLE, LZH or KenCode NDIF plugin: ---- Add support for compressed chunks +--- Add support for chunks compressed with ADC, RLE, LZH or KenCode DART plugin: ---- Add support for compressed chunks +--- Add support for chunks compressed with RLE or LZH Filters: --- Add support for XZ compressed files