///|
/// Byte and target ranges associated with one window.
pub(all) struct WindowIndexEntry {
index : Int
file_offset : Int
encoded_size : Int
target_offset : Int
target_size : Int
source_kind : WindowSourceKind
source_position : Int
source_size : Int
data_offset : Int
instruction_offset : Int
address_offset : Int
} derive(Eq, Debug)
///|
/// Random-access metadata for a parsed delta document.
pub(all) struct DeltaIndex {
file_size : Int
header_size : Int
target_size : Int
source_window_count : Int
target_window_count : Int
independent_window_count : Int
windows : Array[WindowIndexEntry]
} derive(Eq, Debug)
///|
/// Encoding output paired with its parsed structural report.
pub(all) struct EncodeResult {
delta : Bytes
summary : DeltaSummary
trace : DeltaTrace
} derive(Eq, Debug)
///|
/// Decoded target paired with the metadata used to reconstruct it.
pub(all) struct DecodeResult {
target : Bytes
summary : DeltaSummary
trace : DeltaTrace
} derive(Eq, Debug)
///|
fn encoded_window_size(window : ParsedWindow) -> Int raise VcdiffError {
let source_fields = if window.indicator == 0 {
0
} else {
varint_width(window.source_size) + varint_width(window.source_position)
}
1 + source_fields + varint_width(window.delta_length) + window.delta_length
}
///|
/// Builds target-to-file offset mappings without requiring source contents.
pub fn index_delta(delta : Bytes) -> DeltaIndex raise VcdiffError {
let parsed = parse_delta(delta)
let entries : Array[WindowIndexEntry] = []
let mut target_offset = 0
let mut source_window_count = 0
let mut target_window_count = 0
let mut independent_window_count = 0
for index, window in parsed.windows {
let source_kind = window_source_kind(window.indicator)
match source_kind {
SourceDictionary => source_window_count += 1
TargetDictionary => target_window_count += 1
NoDictionary => independent_window_count += 1
}
entries.push({
index,
file_offset: window.offset,
encoded_size: encoded_window_size(window),
target_offset,
target_size: window.target_size,
source_kind,
source_position: window.source_position,
source_size: window.source_size,
data_offset: window.data_offset,
instruction_offset: window.instruction_offset,
address_offset: window.address_offset,
})
target_offset = checked_summary_add(
target_offset,
window.target_size,
window.offset,
)
}
{
file_size: delta.length(),
header_size: parsed.header.length,
target_size: target_offset,
source_window_count,
target_window_count,
independent_window_count,
windows: entries,
}
}
///|
/// Finds the window containing a target byte offset.
pub fn DeltaIndex::window_for_target(
self : DeltaIndex,
target_offset : Int,
) -> WindowIndexEntry? {
if target_offset < 0 || target_offset >= self.target_size {
return None
}
let mut low = 0
let mut high = self.windows.length()
while low < high {
let middle = low + (high - low) / 2
let window = self.windows[middle]
if target_offset < window.target_offset {
high = middle
} else if target_offset >= window.target_offset + window.target_size {
low = middle + 1
} else {
return Some(window)
}
}
None
}
///|
/// Finds the window whose encoded bytes contain a file byte offset.
pub fn DeltaIndex::window_for_file(
self : DeltaIndex,
file_offset : Int,
) -> WindowIndexEntry? {
if file_offset < self.header_size || file_offset >= self.file_size {
return None
}
for window in self.windows {
if file_offset >= window.file_offset &&
file_offset < window.file_offset + window.encoded_size {
return Some(window)
}
}
None
}
///|
fn write_canonical_window(
output : @buffer.Buffer,
window : ParsedWindow,
) -> Unit raise VcdiffError {
output.write_byte(window.indicator.to_byte())
if window.indicator != 0 {
write_varint(output, window.source_size)
write_varint(output, window.source_position)
}
let body = @buffer.Buffer()
write_varint(body, window.target_size)
body.write_byte(b'\x00')
write_varint(body, window.data.length())
write_varint(body, window.instructions.length())
write_varint(body, window.addresses.length())
body.write_bytes(window.data)
body.write_bytes(window.instructions)
body.write_bytes(window.addresses)
write_varint(output, body.length())
output.write_bytes(body.to_bytes())
}
///|
/// Reframes a valid delta with canonical integers and exact section lengths.
///
/// Instruction, data, and address section bytes remain unchanged.
pub fn canonicalize(delta : Bytes) -> Bytes raise VcdiffError {
let parsed = parse_delta(delta)
let output = @buffer.Buffer(size_hint=delta.length())
write_file_header(output)
for window in parsed.windows {
write_canonical_window(output, window)
}
output.to_bytes()
}
///|
/// Returns true when canonical reframing leaves the delta byte-identical.
pub fn is_canonical(delta : Bytes) -> Bool raise VcdiffError {
canonicalize(delta) == delta
}
///|
/// Decodes a delta while preserving its target window boundaries.
pub fn decode_windows(
source : Bytes,
delta : Bytes,
limits : DecodeLimits,
) -> Array[Bytes] raise VcdiffError {
let parsed = parse_delta(delta)
if parsed.windows.length() > limits.max_windows {
raise ResourceLimit(
offset=parsed.header.length,
resource="windows",
limit=limits.max_windows,
)
}
let table = default_code_table()
let output : Array[Byte] = []
let windows : Array[Bytes] = []
for window in parsed.windows {
let dictionary = select_dictionary(source, output, window)
let decoded = decode_window(window, dictionary, limits, table)
if output.length() > limits.max_output_size - decoded.length() {
raise ResourceLimit(
offset=window.offset,
resource="output_size",
limit=limits.max_output_size,
)
}
windows.push(decoded)
append_bytes(output, decoded)
}
windows
}
///|
/// Decodes and returns a validated half-open target byte range.
pub fn decode_range(
source : Bytes,
delta : Bytes,
start : Int,
end : Int,
limits : DecodeLimits,
) -> Bytes raise VcdiffError {
if start < 0 || end < start {
raise InvalidOption(
option="target_range",
reason="must be a non-negative half-open range",
)
}
let target = decode(source, delta, limits)
if end > target.length() {
raise InvalidOption(
option="target_range",
reason="range end exceeds decoded target size",
)
}
target[start:end].to_owned()
}
///|
/// Encodes once and returns the delta, summary, and expanded trace.
pub fn encode_detailed(
source : Bytes,
target : Bytes,
options : EncodeOptions,
) -> EncodeResult raise VcdiffError {
let delta = encode(source, target, options)
{ delta, summary: inspect(delta), trace: trace(delta) }
}
///|
/// Decodes once and returns the target, summary, and expanded trace.
pub fn decode_detailed(
source : Bytes,
delta : Bytes,
limits : DecodeLimits,
) -> DecodeResult raise VcdiffError {
let summary = inspect(delta)
let expanded = trace(delta)
let target = decode(source, delta, limits)
{ target, summary, trace: expanded }
}