1#![allow(non_snake_case)]
2use std::cmp::Ordering;
32use std::io;
33use std::io::Write;
34
35pub fn diff<T: Write>(old: &[u8], new: &[u8], writer: &mut T) -> io::Result<()> {
45 bsdiff_internal(old, new, writer)
46}
47
48#[inline(always)]
49fn usz(i: isize) -> usize {
50 debug_assert!(i >= 0);
51 i as usize
52}
53
54struct SplitParams {
55 start: usize,
56 len: usize,
57}
58
59#[inline]
60fn split_internal(
61 I: &mut [isize],
62 V: &mut [isize],
63 start: usize,
64 len: usize,
65 h: usize,
66) -> Option<SplitParams> {
67 if len < 16 {
68 let mut k = start;
70 while k < start + len {
71 let mut j = 1;
72 let mut x = V[usz(I[k] + h as isize)];
73 let mut i = 1;
74 while k + i < start + len {
75 let v = V[usz(I[k + i] + h as isize)];
76 if v < x {
77 x = v;
78 j = 0;
79 }
80 if v == x {
81 I.swap(k + j, k + i);
82 j += 1;
83 }
84 i += 1;
85 }
86 let kj = (k + j) as isize;
88 for &Ii in &I[k..k + j] {
89 V[usz(Ii)] = kj - 1;
90 }
91 if j == 1 {
92 I[k] = -1;
93 }
94 k += j;
95 }
96 None
97 } else {
98 let x = V[usz(I[start + len / 2] + h as isize)];
100
101 let mut jj = 0;
103 let mut kk = 0;
104 for &Ii in &I[start..start + len] {
105 let v = V[usz(Ii + h as isize)];
106 if v < x {
107 jj += 1;
108 }
109 if v == x {
110 kk += 1;
111 }
112 }
113 let jj = jj + start;
114 let kk = kk + jj;
115
116 let mut j = 0;
118 let mut k = 0;
119 let mut i = start;
120 while i < jj {
121 match V[usz(I[i] + h as isize)].cmp(&x) {
122 Ordering::Less => i += 1,
123 Ordering::Equal => {
124 I.swap(i, jj + j);
125 j += 1;
126 }
127 Ordering::Greater => {
128 I.swap(i, kk + k);
129 k += 1;
130 }
131 }
132 }
133
134 while jj + j < kk {
135 if V[usz(I[jj + j] + h as isize)] == x {
136 j += 1;
137 } else {
138 I.swap(jj + j, kk + k);
139 k += 1;
140 }
141 }
142
143 if jj > start {
145 split(I, V, start, jj - start, h);
146 }
147
148 let kk_minus_1 = (kk - 1) as isize;
150 for &Ii in &I[jj..kk] {
151 V[usz(Ii)] = kk_minus_1;
152 }
153 if jj == kk - 1 {
154 I[jj] = -1;
155 }
156
157 if start + len > kk {
159 Some(SplitParams {
160 start: kk,
161 len: start + len - kk,
162 })
163 } else {
164 None
165 }
166 }
167}
168
169fn split(I: &mut [isize], V: &mut [isize], start: usize, len: usize, h: usize) {
170 let mut ret = Some(SplitParams { start, len });
171 while let Some(params) = ret {
172 ret = split_internal(I, V, params.start, params.len, h);
173 }
174}
175
176fn qsufsort(I: &mut [isize], V: &mut [isize], old: &[u8]) {
178 let mut buckets: [isize; 256] = [0; 256];
180
181 for &o in old {
183 buckets[o as usize] += 1;
184 }
185
186 for i in 1..256 {
188 buckets[i] += buckets[i - 1];
189 }
190
191 for i in (1..256).rev() {
193 buckets[i] = buckets[i - 1];
194 }
195 buckets[0] = 0;
196
197 for (i, &old_byte) in old.iter().enumerate() {
199 buckets[old_byte as usize] += 1;
200 I[usz(buckets[old_byte as usize])] = i as isize;
201 }
202
203 I[0] = old.len() as isize;
204
205 for (i, &old_byte) in old.iter().enumerate() {
207 V[i] = buckets[old_byte as usize];
208 }
209 V[old.len()] = 0;
210
211 for i in 1..256 {
213 if buckets[i] == buckets[i - 1] + 1 {
214 I[usz(buckets[i])] = -1;
215 }
216 }
217 I[0] = -1;
218
219 let mut h = 1;
221 while I[0] != -(old.len() as isize + 1) {
222 let mut len = 0;
223 let mut i = 0;
224 while i < old.len() as isize + 1 {
225 if I[usz(i)] < 0 {
226 len -= I[usz(i)];
227 i = i - I[usz(i)];
228 } else {
229 if len != 0 {
230 I[usz(i - len)] = -len;
231 }
232 len = V[usz(I[usz(i)])] + 1 - i;
233 split(I, V, usz(i), usz(len), h);
234 i += len;
235 len = 0;
236 }
237 }
238 if len != 0 {
239 I[usz(i - len)] = -len;
240 }
241 h += h; }
243
244 for (i, &v) in V[0..=old.len()].iter().enumerate() {
246 I[usz(v)] = i as isize;
247 }
248}
249
250#[inline]
252fn matchlen(old: &[u8], new: &[u8]) -> usize {
253 old.iter()
254 .zip(new)
255 .take_while(|(a, b)| a == b)
256 .count()
257}
258
259fn search(I: &[isize], old: &[u8], new: &[u8]) -> (isize, usize) {
261 if I.len() < 3 {
262 let x = matchlen(&old[usz(I[0])..], new);
263 let y = matchlen(&old[usz(I[I.len() - 1])..], new);
264 if x > y {
265 (I[0], x)
266 } else {
267 (I[I.len() - 1], y)
268 }
269 } else {
270 let mid = (I.len() - 1) / 2;
271 let left = &old[usz(I[mid])..];
272 let right = new;
273 let len_to_check = left.len().min(right.len());
274
275 if left[..len_to_check] < right[..len_to_check] {
276 search(&I[mid..], old, new)
277 } else {
278 search(&I[..=mid], old, new)
279 }
280 }
281}
282
283#[inline]
285fn offtout(x: isize, buf: &mut [u8]) {
286 let x64 = x as i64;
287 if x64 >= 0 {
288 buf.copy_from_slice(&x64.to_le_bytes());
289 } else {
290 let tmp = (-x64) as u64 | (1u64 << 63);
291 buf.copy_from_slice(&tmp.to_le_bytes());
292 }
293}
294
295fn bsdiff_internal(old: &[u8], new: &[u8], writer: &mut dyn Write) -> io::Result<()> {
296 let mut I = vec![0; old.len() + 1];
298 let mut V = vec![0; old.len() + 1];
299
300 qsufsort(&mut I, &mut V, old);
302
303 let mut buffer = Vec::with_capacity(1024);
305
306 let mut scan = 0;
307 let mut len = 0usize;
308 let mut pos = 0usize;
309 let mut lastscan = 0;
310 let mut lastpos = 0;
311 let mut lastoffset = 0isize;
312
313 while scan < new.len() {
314 let mut oldscore = 0;
315 scan += len;
316 let mut scsc = scan;
317
318 while scan < new.len() {
320 let (p, l) = search(&I[..=old.len()], old, &new[scan..]);
321 pos = usz(p);
322 len = l;
323
324 while scsc < scan + len {
326 if scsc as isize + lastoffset < old.len() as _
327 && (old[usz(scsc as isize + lastoffset)] == new[scsc])
328 {
329 oldscore += 1;
330 }
331 scsc += 1;
332 }
333
334 if len == oldscore && (len != 0) || len > oldscore + 8 {
336 break;
337 }
338
339 if scan as isize + lastoffset < old.len() as _
340 && (old[usz(scan as isize + lastoffset)] == new[scan])
341 {
342 oldscore -= 1;
343 }
344 scan += 1;
345 }
346
347 if !(len != oldscore || scan == new.len()) {
348 continue;
349 }
350
351 let mut s = 0;
353 let mut Sf = 0;
354 let mut lenf = 0usize;
355 let mut i = 0usize;
356 while lastscan + i < scan && (lastpos + i < old.len() as _) {
357 if old[lastpos + i] == new[lastscan + i] {
358 s += 1;
359 }
360 i += 1;
361 if s * 2 - i as isize <= Sf * 2 - lenf as isize {
362 continue;
363 }
364 Sf = s;
365 lenf = i;
366 }
367
368 let mut lenb = 0;
370 if scan < new.len() {
371 let mut s = 0isize;
372 let mut Sb = 0;
373 let mut i = 1;
374 while scan >= lastscan + i && (pos >= i) {
375 if old[pos - i] == new[scan - i] {
376 s += 1;
377 }
378 if s * 2 - i as isize > Sb * 2 - lenb as isize {
379 Sb = s;
380 lenb = i;
381 }
382 i += 1;
383 }
384 }
385
386 if lastscan + lenf > scan - lenb {
388 let overlap = lastscan + lenf - (scan - lenb);
389 let mut s = 0;
390 let mut Ss = 0;
391 let mut lens = 0;
392 for i in 0..overlap {
393 if new[lastscan + lenf - overlap + i] == old[lastpos + lenf - overlap + i] {
394 s += 1;
395 }
396 if new[scan - lenb + i] == old[pos - lenb + i] {
397 s -= 1;
398 }
399 if s > Ss {
400 Ss = s;
401 lens = i + 1;
402 }
403 }
404 lenf = lenf + lens - overlap;
405 lenb -= lens;
406 }
407
408 let mut buf: [u8; 24] = [0; 24];
410 offtout(lenf as _, &mut buf[..8]);
411 offtout(
412 scan as isize - lenb as isize - (lastscan + lenf) as isize,
413 &mut buf[8..16],
414 );
415 offtout(
416 pos as isize - lenb as isize - (lastpos + lenf) as isize,
417 &mut buf[16..24],
418 );
419 writer.write_all(&buf[..24])?;
420
421 buffer.clear();
423 buffer.extend(
424 new[lastscan..lastscan + lenf]
425 .iter()
426 .zip(&old[lastpos..lastpos + lenf])
427 .map(|(n, o)| n.wrapping_sub(*o)),
428 );
429 writer.write_all(&buffer)?;
430
431 let write_len = scan - lenb - (lastscan + lenf);
433 let write_start = lastscan + lenf;
434 writer.write_all(&new[write_start..write_start + write_len])?;
435
436 lastscan = scan - lenb;
438 lastpos = pos - lenb;
439 lastoffset = pos as isize - scan as isize;
440 }
441
442 Ok(())
443}