Class: Omnizip::Filters::XzDeltaFilter
- Inherits:
-
Object
- Object
- Omnizip::Filters::XzDeltaFilter
- Defined in:
- lib/omnizip/filters/xz_delta.rb
Overview
XZ Utils Delta filter.
This filter computes byte-wise differences using a 256-byte circular history buffer. It is particularly effective for:
- Stereo audio (distance=4 for 16-bit samples)
- RGB images (distance=3)
- RGBA images (distance=4)
- Multi-channel data with regular patterns
This is DIFFERENT from the 7-Zip Delta filter which uses simple forward differences without a history buffer.
Reference: XZ Utils delta_encoder.c, delta_decoder.c
Constant Summary collapse
- FILTER_ID =
Filter ID for XZ format
0x03- DELTA_DIST_MIN =
Minimum distance value (XZ Utils LZMA_DELTA_DIST_MIN)
1- DELTA_DIST_MAX =
Maximum distance value (XZ Utils LZMA_DELTA_DIST_MAX)
256- HISTORY_SIZE =
History buffer size (always 256 bytes in XZ Utils)
256- DELTA_TYPE_BYTE =
Delta type (only BYTE is supported in XZ Utils)
0
Instance Attribute Summary collapse
-
#distance ⇒ Object
readonly
Returns the value of attribute distance.
Class Method Summary collapse
-
.decode_properties(properties) ⇒ Integer
Decode properties byte to get distance.
-
.encode_properties(distance) ⇒ String
Encode distance to properties byte.
-
.metadata ⇒ Hash
Get metadata about this filter.
Instance Method Summary collapse
-
#decode(data) ⇒ String
Decode (postprocess) data by restoring from differences.
-
#encode(data) ⇒ String
Encode (preprocess) data by computing forward differences.
-
#initialize(distance = DELTA_DIST_MIN) ⇒ XzDeltaFilter
constructor
Initialize the Delta filter.
-
#reset ⇒ void
Reset the filter state.
Constructor Details
#initialize(distance = DELTA_DIST_MIN) ⇒ XzDeltaFilter
Initialize the Delta filter.
82 83 84 85 86 87 88 |
# File 'lib/omnizip/filters/xz_delta.rb', line 82 def initialize(distance = DELTA_DIST_MIN) validate_distance(distance) @distance = distance # Initialize state (matches XZ Utils lzma_delta_coder_init) @pos = 0 @history = ("\x00" * HISTORY_SIZE).b end |
Instance Attribute Details
#distance ⇒ Object (readonly)
Returns the value of attribute distance.
76 77 78 |
# File 'lib/omnizip/filters/xz_delta.rb', line 76 def distance @distance end |
Class Method Details
.decode_properties(properties) ⇒ Integer
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 |
# File 'lib/omnizip/filters/xz_delta.rb', line 177 def decode_properties(properties) unless properties.is_a?(String) && properties.bytesize == 1 raise ArgumentError, "Delta filter requires exactly 1 property byte, got #{properties&.bytesize}" end props_byte = properties.getbyte(0) # XZ Utils: opt->dist = props[0] + LZMA_DELTA_DIST_MIN # where LZMA_DELTA_DIST_MIN = 1 distance = props_byte + DELTA_DIST_MIN # Validate distance is in valid range (inline for class method) unless distance.between?(DELTA_DIST_MIN, DELTA_DIST_MAX) raise ArgumentError, "Invalid distance #{distance}, must be between #{DELTA_DIST_MIN} and #{DELTA_DIST_MAX}" end distance end |
.encode_properties(distance) ⇒ String
Encode distance to properties byte.
XZ Utils encodes distance as: props = dist - 1
Reference: XZ Utils delta_encoder.c:lzma_delta_props_encode
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/omnizip/filters/xz_delta.rb', line 206 def encode_properties(distance) # Validate distance (inline for class method) unless distance.is_a?(Integer) raise ArgumentError, "Distance must be an integer, got #{distance.class}" end unless distance.between?(DELTA_DIST_MIN, DELTA_DIST_MAX) raise ArgumentError, "Distance must be between #{DELTA_DIST_MIN} and #{DELTA_DIST_MAX}, got #{distance}" end # XZ Utils: out[0] = opt->dist - LZMA_DELTA_DIST_MIN # where LZMA_DELTA_DIST_MIN = 1 props_byte = distance - DELTA_DIST_MIN [props_byte].pack("C") end |
.metadata ⇒ Hash
Get metadata about this filter.
228 229 230 231 232 233 234 235 236 |
# File 'lib/omnizip/filters/xz_delta.rb', line 228 def { name: "XZ Delta", description: "XZ Utils Delta filter with 256-byte circular history buffer", filter_id: FILTER_ID, typical_usage: "WAV audio (distance=4), BMP images (distance=3), " \ "multi-channel data with regular patterns", } end |
Instance Method Details
#decode(data) ⇒ String
Decode (postprocess) data by restoring from differences.
For each byte:
buffer[i] += history[(distance + pos) & 0xFF] (mod 256)
history[pos & 0xFF] = buffer[i]
pos--
Reference: XZ Utils delta_decoder.c:decode_buffer
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/omnizip/filters/xz_delta.rb', line 134 def decode(data) return data.dup.b if data.empty? result = data.dup.b data.bytes.each_with_index do |byte, i| # Get historical value from distance positions back tmp = @history.getbyte((@distance + @pos) & 0xFF) # Restore original value by adding the difference result.setbyte(i, (byte + tmp) & 0xFF) # Store restored byte in history @history.setbyte(@pos & 0xFF, result.getbyte(i)) # Move position backward (wraps via & 0xFF) @pos = (@pos - 1) & 0xFF end result end |
#encode(data) ⇒ String
Encode (preprocess) data by computing forward differences.
For each byte:
tmp = history[(distance + pos) & 0xFF]
history[pos & 0xFF] = in[i]
out[i] = in[i] - tmp (mod 256)
pos--
Reference: XZ Utils delta_encoder.c:copy_and_encode
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/omnizip/filters/xz_delta.rb', line 102 def encode(data) return data.dup.b if data.empty? result = data.dup.b data.bytes.each_with_index do |byte, i| # Get historical value from distance positions back tmp = @history.getbyte((@distance + @pos) & 0xFF) # Store current byte in history @history.setbyte(@pos & 0xFF, byte) # Output is the difference result.setbyte(i, (byte - tmp) & 0xFF) # Move position backward (wraps via & 0xFF) @pos = (@pos - 1) & 0xFF end result end |
#reset ⇒ void
This method returns an undefined value.
Reset the filter state.
This clears the history buffer and resets position to 0. Used when initializing a new filter chain.
161 162 163 164 |
# File 'lib/omnizip/filters/xz_delta.rb', line 161 def reset @pos = 0 @history = ("\x00" * HISTORY_SIZE).b end |