
RFC 3284-compliant VCDIFF decoder enabling one-shot, reusable and streaming delta decoding, structural inspection, address cache support, Adler-32 validation, and robust typed error handling.
A Kotlin Multiplatform implementation of a VCDIFF (RFC 3284) decoder library for efficient binary differencing and compression.
This library provides a VCDIFF decoder that can decode delta files created according to RFC 3284 - The VCDIFF Generic Differencing and Compression Data Format. VCDIFF is a format for expressing one data stream as a variant of another data stream, commonly used for binary differencing, compression, and patch applications.
The library provides one-shot decoding, reusable decoder instances, a streaming decoder for incremental processing, and a structural inspection API.
xdelta3 -e -S -A (no secondary compression, no application header)dependencies {
implementation("com.ably.vcdiff:vcdiff:0.1.0")
}dependencies {
implementation 'com.ably.vcdiff:vcdiff:0.1.0'
}This repository includes the VCDIFF test suite as a git submodule. To clone the repository with all test cases:
git clone --recursive https://github.com/ably/vcdiff-kotlin.gitIf you've already cloned the repository without the submodule, initialize it:
git submodule update --init --recursiveTo update the test suite submodule to the latest version:
git submodule update --remoteimport com.ably.vcdiff.decode
import java.io.File
fun main() {
val source = File("original.txt").readBytes()
val delta = File("changes.vcdiff").readBytes()
val result = decode(source, delta)
File("result.txt").writeBytes(result)
}For decoding multiple deltas against the same source:
import com.ably.vcdiff.VcdiffDecoder
import java.io.File
fun main() {
val source = File("original.txt").readBytes()
val decoder = VcdiffDecoder(source)
val target1 = decoder.decode(File("delta1.vcdiff").readBytes())
val target2 = decoder.decode(File("delta2.vcdiff").readBytes())
}For processing delta bytes incrementally as they arrive:
import com.ably.vcdiff.VcdiffStreamingDecoder
import java.io.ByteArrayOutputStream
fun main() {
val source = File("original.txt").readBytes()
val decoder = VcdiffStreamingDecoder(source)
val output = ByteArrayOutputStream()
// Feed chunks as they arrive
output.write(decoder.append(chunk1))
output.write(decoder.append(chunk2))
output.write(decoder.append(chunk3))
// Signal end of stream
output.write(decoder.finish())
val result = output.toByteArray()
}The decoder provides specific exception types for different error conditions:
import com.ably.vcdiff.*
fun main() {
try {
val target = decode(source, delta)
} catch (e: InvalidMagicException) {
println("Invalid VCDIFF file: $e")
} catch (e: UnsupportedVersionException) {
println("Unsupported VCDIFF version: $e")
} catch (e: ChecksumMismatchException) {
println("Checksum failed: expected ${e.expected}, got ${e.actual}")
} catch (e: InvalidFormatException) {
println("Malformed delta: $e")
} catch (e: VcdiffException) {
println("VCDIFF error: $e")
}
}Parse and inspect the structure of a VCDIFF delta without full decoding:
import com.ably.vcdiff.parseDelta
import java.io.File
fun main() {
val delta = File("changes.vcdiff").readBytes()
val parsed = parseDelta(delta)
println("Version: ${parsed.header.version}")
println("Windows: ${parsed.windows.size}")
for (window in parsed.windows) {
println(" Target length: ${window.targetWindowLength}")
println(" Instructions: ${window.instructions.size}")
}
}Decodes a VCDIFF delta file using the provided source data and returns the reconstructed target data.
Parameters:
source: The original source data (may be empty for deltas that don't reference source)delta: The VCDIFF delta file dataReturns:
Throws:
VcdiffException if decoding fails (malformed delta, checksum validation failure, etc.)Parses a VCDIFF delta into its structural components without performing full decoding. Useful for debugging and tooling.
Parameters:
delta: The VCDIFF delta file dataReturns:
ParsedDelta containing the header and list of windows with their instructionsCreates a new decoder instance with the specified source data. Useful for decoding multiple deltas against the same source.
Methods:
decode(delta: ByteArray): ByteArray - Decodes a single VCDIFF delta using the decoder's source dataCreates a streaming decoder that accepts delta bytes incrementally. Emits reconstructed target bytes as soon as complete windows are decoded.
Methods:
append(data: ByteArray): ByteArray - Feed delta bytes; returns any decoded output availablefinish(): ByteArray - Signal end of stream; returns any remaining decoded outputVcdiffException: Base exception for all VCDIFF errorsInvalidMagicException: Invalid VCDIFF magic bytesUnsupportedVersionException: Unsupported VCDIFF versionInvalidFormatException: Malformed delta structure (truncated data, bad lengths, etc.)ChecksumMismatchException: Adler-32 checksum validation failure (includes expected and actual fields)header: Header - VCDIFF file headerwindows: List<Window> - List of delta windowsversion: Byte - VCDIFF version (always 0)indicator: HeaderIndicator - Header flagssourceSegmentSize: Long - Size of source segment referencedsourceSegmentPosition: Long - Offset into source datatargetWindowLength: Long - Expected target window sizehasChecksum: Boolean - Whether Adler-32 checksum is presentchecksum: Long - Adler-32 checksum valueinstructions: List<Instruction> - Decoded instructionsInstruction.Add(size: Long, data: ByteArray) - Add literal bytesInstruction.Copy(size: Long, mode: Int, address: Long) - Copy from source or targetInstruction.Run(size: Long, byte: Byte) - Repeat a single byteTo run all tests:
gradle testTo run with verbose output:
gradle test --infoTo run only the integration tests:
gradle test --tests "com.ably.vcdiff.VcdiffTest"To run only the fuzz tests:
gradle test --tests "com.ably.vcdiff.FuzzTest"The test suite includes:
parseDelta API validationThis is a decoder-only library. To create compatible VCDIFF delta files, use tools such as xdelta3:
# Create a VCDIFF delta (compatible with this decoder)
xdelta3 -e -S -A -s original.txt modified.txt delta.vcdiffContributions are welcomed. Please follow these guidelines.
git clone --recursive <your-fork-url>
git checkout -b feature/your-feature-name
Ensure your contribution passes all checks:
# Run all tests
gradle test
# Check for compilation errors
gradle compileKotlinWhen reporting bugs, please include:
For new features, please:
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
A Kotlin Multiplatform implementation of a VCDIFF (RFC 3284) decoder library for efficient binary differencing and compression.
This library provides a VCDIFF decoder that can decode delta files created according to RFC 3284 - The VCDIFF Generic Differencing and Compression Data Format. VCDIFF is a format for expressing one data stream as a variant of another data stream, commonly used for binary differencing, compression, and patch applications.
The library provides one-shot decoding, reusable decoder instances, a streaming decoder for incremental processing, and a structural inspection API.
xdelta3 -e -S -A (no secondary compression, no application header)dependencies {
implementation("com.ably.vcdiff:vcdiff:0.1.0")
}dependencies {
implementation 'com.ably.vcdiff:vcdiff:0.1.0'
}This repository includes the VCDIFF test suite as a git submodule. To clone the repository with all test cases:
git clone --recursive https://github.com/ably/vcdiff-kotlin.gitIf you've already cloned the repository without the submodule, initialize it:
git submodule update --init --recursiveTo update the test suite submodule to the latest version:
git submodule update --remoteimport com.ably.vcdiff.decode
import java.io.File
fun main() {
val source = File("original.txt").readBytes()
val delta = File("changes.vcdiff").readBytes()
val result = decode(source, delta)
File("result.txt").writeBytes(result)
}For decoding multiple deltas against the same source:
import com.ably.vcdiff.VcdiffDecoder
import java.io.File
fun main() {
val source = File("original.txt").readBytes()
val decoder = VcdiffDecoder(source)
val target1 = decoder.decode(File("delta1.vcdiff").readBytes())
val target2 = decoder.decode(File("delta2.vcdiff").readBytes())
}For processing delta bytes incrementally as they arrive:
import com.ably.vcdiff.VcdiffStreamingDecoder
import java.io.ByteArrayOutputStream
fun main() {
val source = File("original.txt").readBytes()
val decoder = VcdiffStreamingDecoder(source)
val output = ByteArrayOutputStream()
// Feed chunks as they arrive
output.write(decoder.append(chunk1))
output.write(decoder.append(chunk2))
output.write(decoder.append(chunk3))
// Signal end of stream
output.write(decoder.finish())
val result = output.toByteArray()
}The decoder provides specific exception types for different error conditions:
import com.ably.vcdiff.*
fun main() {
try {
val target = decode(source, delta)
} catch (e: InvalidMagicException) {
println("Invalid VCDIFF file: $e")
} catch (e: UnsupportedVersionException) {
println("Unsupported VCDIFF version: $e")
} catch (e: ChecksumMismatchException) {
println("Checksum failed: expected ${e.expected}, got ${e.actual}")
} catch (e: InvalidFormatException) {
println("Malformed delta: $e")
} catch (e: VcdiffException) {
println("VCDIFF error: $e")
}
}Parse and inspect the structure of a VCDIFF delta without full decoding:
import com.ably.vcdiff.parseDelta
import java.io.File
fun main() {
val delta = File("changes.vcdiff").readBytes()
val parsed = parseDelta(delta)
println("Version: ${parsed.header.version}")
println("Windows: ${parsed.windows.size}")
for (window in parsed.windows) {
println(" Target length: ${window.targetWindowLength}")
println(" Instructions: ${window.instructions.size}")
}
}Decodes a VCDIFF delta file using the provided source data and returns the reconstructed target data.
Parameters:
source: The original source data (may be empty for deltas that don't reference source)delta: The VCDIFF delta file dataReturns:
Throws:
VcdiffException if decoding fails (malformed delta, checksum validation failure, etc.)Parses a VCDIFF delta into its structural components without performing full decoding. Useful for debugging and tooling.
Parameters:
delta: The VCDIFF delta file dataReturns:
ParsedDelta containing the header and list of windows with their instructionsCreates a new decoder instance with the specified source data. Useful for decoding multiple deltas against the same source.
Methods:
decode(delta: ByteArray): ByteArray - Decodes a single VCDIFF delta using the decoder's source dataCreates a streaming decoder that accepts delta bytes incrementally. Emits reconstructed target bytes as soon as complete windows are decoded.
Methods:
append(data: ByteArray): ByteArray - Feed delta bytes; returns any decoded output availablefinish(): ByteArray - Signal end of stream; returns any remaining decoded outputVcdiffException: Base exception for all VCDIFF errorsInvalidMagicException: Invalid VCDIFF magic bytesUnsupportedVersionException: Unsupported VCDIFF versionInvalidFormatException: Malformed delta structure (truncated data, bad lengths, etc.)ChecksumMismatchException: Adler-32 checksum validation failure (includes expected and actual fields)header: Header - VCDIFF file headerwindows: List<Window> - List of delta windowsversion: Byte - VCDIFF version (always 0)indicator: HeaderIndicator - Header flagssourceSegmentSize: Long - Size of source segment referencedsourceSegmentPosition: Long - Offset into source datatargetWindowLength: Long - Expected target window sizehasChecksum: Boolean - Whether Adler-32 checksum is presentchecksum: Long - Adler-32 checksum valueinstructions: List<Instruction> - Decoded instructionsInstruction.Add(size: Long, data: ByteArray) - Add literal bytesInstruction.Copy(size: Long, mode: Int, address: Long) - Copy from source or targetInstruction.Run(size: Long, byte: Byte) - Repeat a single byteTo run all tests:
gradle testTo run with verbose output:
gradle test --infoTo run only the integration tests:
gradle test --tests "com.ably.vcdiff.VcdiffTest"To run only the fuzz tests:
gradle test --tests "com.ably.vcdiff.FuzzTest"The test suite includes:
parseDelta API validationThis is a decoder-only library. To create compatible VCDIFF delta files, use tools such as xdelta3:
# Create a VCDIFF delta (compatible with this decoder)
xdelta3 -e -S -A -s original.txt modified.txt delta.vcdiffContributions are welcomed. Please follow these guidelines.
git clone --recursive <your-fork-url>
git checkout -b feature/your-feature-name
Ensure your contribution passes all checks:
# Run all tests
gradle test
# Check for compilation errors
gradle compileKotlinWhen reporting bugs, please include:
For new features, please:
This project is licensed under the Apache License 2.0. See the LICENSE file for details.