1#![allow(non_snake_case)]
2use std::cmp::Ordering;
32use std::io;
33use std::io::Write;
34
35use crate::bsdf2_writer::{Bsdf2Writer, CompressionAlgorithm, ControlEntry};
36
37pub fn diff<T: Write>(old: &[u8], new: &[u8], writer: &mut T) -> io::Result<()> {
42 bsdiff_internal(old, new, writer)
43}
44
45pub fn diff_bsdiff40<T: Write>(old: &[u8], new: &[u8], writer: &mut T) -> io::Result<()> {
47 let mut patch_writer = Bsdf2Writer::new_legacy();
48 bsdiff_with_writer(old, new, &mut patch_writer)?;
49 patch_writer.close(writer)
50}
51
52pub fn diff_bsdf2<T: Write>(
54 old: &[u8],
55 new: &[u8],
56 writer: &mut T,
57 ctrl_alg: CompressionAlgorithm,
58 diff_alg: CompressionAlgorithm,
59 extra_alg: CompressionAlgorithm,
60) -> io::Result<()> {
61 let mut patch_writer = Bsdf2Writer::new(ctrl_alg, diff_alg, extra_alg);
62 bsdiff_with_writer(old, new, &mut patch_writer)?;
63 patch_writer.close(writer)
64}
65
66pub fn diff_bsdf2_uniform<T: Write>(
68 old: &[u8],
69 new: &[u8],
70 writer: &mut T,
71 alg: CompressionAlgorithm,
72) -> io::Result<()> {
73 diff_bsdf2(old, new, writer, alg, alg, alg)
74}
75
76#[inline(always)]
77fn usz(i: isize) -> usize {
78 debug_assert!(i >= 0);
79 i as usize
80}
81
82struct SplitParams {
83 start: usize,
84 len: usize,
85}
86
87#[inline]
88fn split_internal(
89 I: &mut [isize],
90 V: &mut [isize],
91 start: usize,
92 len: usize,
93 h: usize,
94) -> Option<SplitParams> {
95 if len < 16 {
96 let mut k = start;
97 while k < start + len {
98 let mut j = 1;
99 let mut x = V[usz(I[k] + h as isize)];
100 let mut i = 1;
101 while k + i < start + len {
102 let v = V[usz(I[k + i] + h as isize)];
103 if v < x {
104 x = v;
105 j = 0;
106 }
107 if v == x {
108 I.swap(k + j, k + i);
109 j += 1;
110 }
111 i += 1;
112 }
113 let kj = (k + j) as isize;
114 for &Ii in &I[k..k + j] {
115 V[usz(Ii)] = kj - 1;
116 }
117 if j == 1 {
118 I[k] = -1;
119 }
120 k += j;
121 }
122 None
123 } else {
124 let x = V[usz(I[start + len / 2] + h as isize)];
125
126 let mut jj = 0;
127 let mut kk = 0;
128 for &Ii in &I[start..start + len] {
129 let v = V[usz(Ii + h as isize)];
130 if v < x {
131 jj += 1;
132 }
133 if v == x {
134 kk += 1;
135 }
136 }
137 let jj = jj + start;
138 let kk = kk + jj;
139
140 let mut j = 0;
141 let mut k = 0;
142 let mut i = start;
143 while i < jj {
144 match V[usz(I[i] + h as isize)].cmp(&x) {
145 Ordering::Less => i += 1,
146 Ordering::Equal => {
147 I.swap(i, jj + j);
148 j += 1;
149 }
150 Ordering::Greater => {
151 I.swap(i, kk + k);
152 k += 1;
153 }
154 }
155 }
156
157 while jj + j < kk {
158 if V[usz(I[jj + j] + h as isize)] == x {
159 j += 1;
160 } else {
161 I.swap(jj + j, kk + k);
162 k += 1;
163 }
164 }
165
166 if jj > start {
167 split(I, V, start, jj - start, h);
168 }
169
170 let kk_minus_1 = (kk - 1) as isize;
171 for &Ii in &I[jj..kk] {
172 V[usz(Ii)] = kk_minus_1;
173 }
174 if jj == kk - 1 {
175 I[jj] = -1;
176 }
177
178 if start + len > kk {
179 Some(SplitParams {
180 start: kk,
181 len: start + len - kk,
182 })
183 } else {
184 None
185 }
186 }
187}
188
189fn split(I: &mut [isize], V: &mut [isize], start: usize, len: usize, h: usize) {
190 let mut ret = Some(SplitParams { start, len });
191 while let Some(params) = ret {
192 ret = split_internal(I, V, params.start, params.len, h);
193 }
194}
195
196fn qsufsort(I: &mut [isize], V: &mut [isize], old: &[u8]) {
197 let mut buckets: [isize; 256] = [0; 256];
198
199 for &o in old {
200 buckets[o as usize] += 1;
201 }
202
203 for i in 1..256 {
204 buckets[i] += buckets[i - 1];
205 }
206
207 for i in (1..256).rev() {
208 buckets[i] = buckets[i - 1];
209 }
210 buckets[0] = 0;
211
212 for (i, &old_byte) in old.iter().enumerate() {
213 buckets[old_byte as usize] += 1;
214 I[usz(buckets[old_byte as usize])] = i as isize;
215 }
216
217 I[0] = old.len() as isize;
218
219 for (i, &old_byte) in old.iter().enumerate() {
220 V[i] = buckets[old_byte as usize];
221 }
222 V[old.len()] = 0;
223
224 for i in 1..256 {
225 if buckets[i] == buckets[i - 1] + 1 {
226 I[usz(buckets[i])] = -1;
227 }
228 }
229 I[0] = -1;
230
231 let mut h = 1;
232 while I[0] != -(old.len() as isize + 1) {
233 let mut len = 0;
234 let mut i = 0;
235 while i < old.len() as isize + 1 {
236 if I[usz(i)] < 0 {
237 len -= I[usz(i)];
238 i = i - I[usz(i)];
239 } else {
240 if len != 0 {
241 I[usz(i - len)] = -len;
242 }
243 len = V[usz(I[usz(i)])] + 1 - i;
244 split(I, V, usz(i), usz(len), h);
245 i += len;
246 len = 0;
247 }
248 }
249 if len != 0 {
250 I[usz(i - len)] = -len;
251 }
252 h += h;
253 }
254
255 for (i, &v) in V[0..=old.len()].iter().enumerate() {
256 I[usz(v)] = i as isize;
257 }
258}
259
260#[inline]
261fn matchlen(old: &[u8], new: &[u8]) -> usize {
262 old.iter()
263 .zip(new)
264 .take_while(|(a, b)| a == b)
265 .count()
266}
267
268fn search(I: &[isize], old: &[u8], new: &[u8]) -> (isize, usize) {
269 if I.len() < 3 {
270 let x = matchlen(&old[usz(I[0])..], new);
271 let y = matchlen(&old[usz(I[I.len() - 1])..], new);
272 if x > y {
273 (I[0], x)
274 } else {
275 (I[I.len() - 1], y)
276 }
277 } else {
278 let mid = (I.len() - 1) / 2;
279 let left = &old[usz(I[mid])..];
280 let right = new;
281 let len_to_check = left.len().min(right.len());
282
283 if left[..len_to_check] < right[..len_to_check] {
284 search(&I[mid..], old, new)
285 } else {
286 search(&I[..=mid], old, new)
287 }
288 }
289}
290
291#[inline]
293fn offtout(x: isize, buf: &mut [u8]) {
294 let x64 = x as i64;
295 if x64 >= 0 {
296 buf.copy_from_slice(&x64.to_le_bytes());
297 } else {
298 let tmp = (-x64) as u64 | (1u64 << 63);
299 buf.copy_from_slice(&tmp.to_le_bytes());
300 }
301}
302
303fn bsdiff_internal(old: &[u8], new: &[u8], writer: &mut dyn Write) -> io::Result<()> {
305 let mut I = vec![0; old.len() + 1];
306 let mut V = vec![0; old.len() + 1];
307
308 qsufsort(&mut I, &mut V, old);
309
310 let mut buffer = Vec::with_capacity(1024);
311
312 let mut scan = 0;
313 let mut len = 0usize;
314 let mut pos = 0usize;
315 let mut lastscan = 0;
316 let mut lastpos = 0;
317 let mut lastoffset = 0isize;
318
319 while scan < new.len() {
320 let mut oldscore = 0;
321 scan += len;
322 let mut scsc = scan;
323
324 while scan < new.len() {
325 let (p, l) = search(&I[..=old.len()], old, &new[scan..]);
326 pos = usz(p);
327 len = l;
328
329 while scsc < scan + len {
330 if scsc as isize + lastoffset < old.len() as _
331 && (old[usz(scsc as isize + lastoffset)] == new[scsc])
332 {
333 oldscore += 1;
334 }
335 scsc += 1;
336 }
337
338 if len == oldscore && (len != 0) || len > oldscore + 8 {
339 break;
340 }
341
342 if scan as isize + lastoffset < old.len() as _
343 && (old[usz(scan as isize + lastoffset)] == new[scan])
344 {
345 oldscore -= 1;
346 }
347 scan += 1;
348 }
349
350 if !(len != oldscore || scan == new.len()) {
351 continue;
352 }
353
354 let mut s = 0;
355 let mut Sf = 0;
356 let mut lenf = 0usize;
357 let mut i = 0usize;
358 while lastscan + i < scan && (lastpos + i < old.len() as _) {
359 if old[lastpos + i] == new[lastscan + i] {
360 s += 1;
361 }
362 i += 1;
363 if s * 2 - i as isize <= Sf * 2 - lenf as isize {
364 continue;
365 }
366 Sf = s;
367 lenf = i;
368 }
369
370 let mut lenb = 0;
371 if scan < new.len() {
372 let mut s = 0isize;
373 let mut Sb = 0;
374 let mut i = 1;
375 while scan >= lastscan + i && (pos >= i) {
376 if old[pos - i] == new[scan - i] {
377 s += 1;
378 }
379 if s * 2 - i as isize > Sb * 2 - lenb as isize {
380 Sb = s;
381 lenb = i;
382 }
383 i += 1;
384 }
385 }
386
387 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;
437 lastpos = pos - lenb;
438 lastoffset = pos as isize - scan as isize;
439 }
440
441 Ok(())
442}
443
444fn bsdiff_with_writer(old: &[u8], new: &[u8], writer: &mut Bsdf2Writer) -> io::Result<()> {
446 let mut I = vec![0; old.len() + 1];
447 let mut V = vec![0; old.len() + 1];
448
449 qsufsort(&mut I, &mut V, old);
450
451 let mut buffer = Vec::with_capacity(1024);
452
453 let mut scan = 0;
454 let mut len = 0usize;
455 let mut pos = 0usize;
456 let mut lastscan = 0;
457 let mut lastpos = 0;
458 let mut lastoffset = 0isize;
459
460 while scan < new.len() {
461 let mut oldscore = 0;
462 scan += len;
463 let mut scsc = scan;
464
465 while scan < new.len() {
466 let (p, l) = search(&I[..=old.len()], old, &new[scan..]);
467 pos = usz(p);
468 len = l;
469
470 while scsc < scan + len {
471 if scsc as isize + lastoffset < old.len() as _
472 && (old[usz(scsc as isize + lastoffset)] == new[scsc])
473 {
474 oldscore += 1;
475 }
476 scsc += 1;
477 }
478
479 if len == oldscore && (len != 0) || len > oldscore + 8 {
480 break;
481 }
482
483 if scan as isize + lastoffset < old.len() as _
484 && (old[usz(scan as isize + lastoffset)] == new[scan])
485 {
486 oldscore -= 1;
487 }
488 scan += 1;
489 }
490
491 if !(len != oldscore || scan == new.len()) {
492 continue;
493 }
494
495 let mut s = 0;
496 let mut Sf = 0;
497 let mut lenf = 0usize;
498 let mut i = 0usize;
499 while lastscan + i < scan && (lastpos + i < old.len() as _) {
500 if old[lastpos + i] == new[lastscan + i] {
501 s += 1;
502 }
503 i += 1;
504 if s * 2 - i as isize <= Sf * 2 - lenf as isize {
505 continue;
506 }
507 Sf = s;
508 lenf = i;
509 }
510
511 let mut lenb = 0;
512 if scan < new.len() {
513 let mut s = 0isize;
514 let mut Sb = 0;
515 let mut i = 1;
516 while scan >= lastscan + i && (pos >= i) {
517 if old[pos - i] == new[scan - i] {
518 s += 1;
519 }
520 if s * 2 - i as isize > Sb * 2 - lenb as isize {
521 Sb = s;
522 lenb = i;
523 }
524 i += 1;
525 }
526 }
527
528 if lastscan + lenf > scan - lenb {
529 let overlap = lastscan + lenf - (scan - lenb);
530 let mut s = 0;
531 let mut Ss = 0;
532 let mut lens = 0;
533 for i in 0..overlap {
534 if new[lastscan + lenf - overlap + i] == old[lastpos + lenf - overlap + i] {
535 s += 1;
536 }
537 if new[scan - lenb + i] == old[pos - lenb + i] {
538 s -= 1;
539 }
540 if s > Ss {
541 Ss = s;
542 lens = i + 1;
543 }
544 }
545 lenf = lenf + lens - overlap;
546 lenb -= lens;
547 }
548
549 let entry = ControlEntry {
551 diff_size: lenf as i64,
552 extra_size: (scan as isize - lenb as isize - (lastscan + lenf) as isize) as i64,
553 offset_increment: (pos as isize - lenb as isize - (lastpos + lenf) as isize) as i64,
554 };
555 writer.add_control_entry(entry)?;
556
557 buffer.clear();
559 buffer.extend(
560 new[lastscan..lastscan + lenf]
561 .iter()
562 .zip(&old[lastpos..lastpos + lenf])
563 .map(|(n, o)| n.wrapping_sub(*o)),
564 );
565 writer.write_diff_stream(&buffer)?;
566
567 let write_len = scan - lenb - (lastscan + lenf);
569 let write_start = lastscan + lenf;
570 writer.write_extra_stream(&new[write_start..write_start + write_len])?;
571
572 lastscan = scan - lenb;
573 lastpos = pos - lenb;
574 lastoffset = pos as isize - scan as isize;
575 }
576
577 Ok(())
578}