/// <param name="sparseIndex">one-based index</param> /// <returns>True if the write was complete (i.e. this was the last sparse)</returns> public static bool WriteCompressedSparse(Stream input, Stream output, long maxSparseSize) { // We will write the header later output.Seek(SparseHeader.Length, SeekOrigin.Begin); long currentSparseSize = SparseHeader.Length; uint chunkCount = 0; if (input.Position != 0) { WriteDontCareChunk(output, (uint)(input.Position / BlockSize)); chunkCount++; } MemoryStream rawChunk = new MemoryStream(); byte[] fill = null; int fillCount = 0; // We keep reading as long as we have a room for an additional chunk // (the largest chunk is a raw chunk) while (currentSparseSize + ChunkHeader.Length + BlockSize <= maxSparseSize && input.Position < input.Length) { byte[] block = new byte[BlockSize]; input.Read(block, 0, BlockSize); byte[] currentFill = SparseCompressionHelper.TryToCompressBlock(block); if (fill != null) { if (currentFill != null) { if (ByteUtils.AreByteArraysEqual(fill, currentFill)) { fillCount++; } else { WriteFillChunk(output, fill, (uint)fillCount); chunkCount++; fillCount = 1; fill = currentFill; currentSparseSize += ChunkHeader.Length + 4; } } else { WriteFillChunk(output, fill, (uint)fillCount); chunkCount++; ByteWriter.WriteBytes(rawChunk, block); fill = null; fillCount = 0; currentSparseSize += ChunkHeader.Length + BlockSize; } } else // fill == null { if (currentFill != null) { WriteRawChunk(output, rawChunk); chunkCount++; rawChunk = new MemoryStream(); fillCount = 1; fill = currentFill; currentSparseSize += ChunkHeader.Length + 4; } else { ByteWriter.WriteBytes(rawChunk, block); currentSparseSize += BlockSize; } } } if (rawChunk.Length > 0) { WriteRawChunk(output, rawChunk); chunkCount++; } else { WriteFillChunk(output, fill, (uint)fillCount); chunkCount++; } bool complete = (input.Position == input.Length); if (!complete) { WriteDontCareChunk(output, (uint)((input.Length - input.Position) / BlockSize)); chunkCount++; } output.Seek(0, SeekOrigin.Begin); SparseHeader sparseHeader = new SparseHeader(); sparseHeader.BlockSize = BlockSize; sparseHeader.TotalBlocks = (uint)(input.Length / BlockSize); sparseHeader.TotalChunks = chunkCount; sparseHeader.WriteBytes(output); output.Close(); return(complete); }
private static void Compress(string inputPath, string outputPath, long maxSparseSize) { FileStream input; try { input = File.Open(inputPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } catch (IOException) { Console.WriteLine("Cannot open " + inputPath); return; } catch (UnauthorizedAccessException) { Console.WriteLine("Cannot open {0} - Access Denied", inputPath); return; } if (input.Length % SparseCompressionHelper.BlockSize > 0) { Console.WriteLine("Image size is not a multiple of {0} bytes", SparseCompressionHelper.BlockSize); return; } if (!Directory.Exists(outputPath)) { Console.WriteLine("Output directory does not exist"); return; } if (!outputPath.EndsWith(":") && !outputPath.EndsWith(@"\")) { outputPath += @"\"; } string imageFileName = Path.GetFileName(inputPath); string prefix = outputPath + imageFileName + "_sparsechunk"; int sparseIndex = 1; while (true) { string sparsePath = prefix + sparseIndex.ToString(); FileStream output; try { output = File.Open(sparsePath, FileMode.Create, FileAccess.ReadWrite, FileShare.None); output.SetLength(0); } catch (IOException) { Console.WriteLine("Cannot open " + sparsePath); return; } catch (UnauthorizedAccessException) { Console.WriteLine("Cannot open {0} - Access Denied", sparsePath); return; } Console.WriteLine("Writing: {0}", sparsePath); bool complete = SparseCompressionHelper.WriteCompressedSparse(input, output, maxSparseSize); if (complete) { break; } sparseIndex++; } input.Close(); }