sqlite_compressions/
bsdiffraw.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
use std::io::Cursor;

use rusqlite::Error::UserFunctionError;

use crate::common_diff::{register_differ, Differ};
use crate::rusqlite::{Connection, Result};

/// Register the `bsdiffraw` and `bspatchraw` SQL functions with the given `SQLite` connection.
/// The `bsdiffraw` function takes two arguments, and returns the [BSDiff delta](https://github.com/mendsley/bsdiff#readme) (blob) of the binary difference.
/// The arguments can be either a string or a blob.
/// If any of the arguments are `NULL`, the result is `NULL`.
///
/// # Example
///
/// ```
/// # use sqlite_compressions::rusqlite::{Connection, Result};
/// # use sqlite_compressions::register_bsdiffraw_functions;
/// # fn main() -> Result<()> {
/// let db = Connection::open_in_memory()?;
/// register_bsdiffraw_functions(&db)?;
/// let result: String = db.query_row("SELECT hex(bsdiffraw('abc013479zz', 'abc23456789zzf'))", [], |r| r.get(0))?;
/// assert_eq!(result.as_str(), "03000000000000000B00000000000000070000000000000000000032333435363738397A7A66");
/// let result: String = db.query_row("SELECT hex(bspatchraw('abc013479zz', bsdiffraw('abc013479zz', 'abc23456789zzf')))", [], |r| r.get(0))?;
/// assert_eq!(result.as_str(), "61626332333435363738397A7A66");
/// let result: Vec<u8> = db.query_row("SELECT bspatchraw('013479', bsdiffraw('013479', '23456789'))", [], |r| r.get(0))?;
/// let expected = b"23456789";
/// assert_eq!(result, expected);
/// # Ok(())
/// # }
/// ```
pub fn register_bsdiffraw_functions(conn: &Connection) -> Result<()> {
    register_differ::<BsdiffRawDiffer>(conn)
}

pub struct BsdiffRawDiffer;

impl Differ for BsdiffRawDiffer {
    fn diff_name() -> &'static str {
        "bsdiffraw"
    }

    fn patch_name() -> &'static str {
        "bspatchraw"
    }

    fn diff(source: &[u8], target: &[u8]) -> Result<Vec<u8>> {
        let mut patch = Vec::new();
        bsdiff::diff(source, target, &mut patch).map_err(|e| UserFunctionError(e.into()))?;
        Ok(patch)
    }

    fn patch(source: &[u8], patch: &[u8]) -> Result<Vec<u8>> {
        let mut target = Vec::new();
        bsdiff::patch(source, &mut Cursor::new(patch), &mut target)
            .map_err(|e| UserFunctionError(e.into()))?;
        Ok(target)
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_diff() {
        let source = b"abc013479zz";
        let target = b"abc23456789zzf";
        let patch = BsdiffRawDiffer::diff(source, target).unwrap();
        let expected = b"\x03\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x32\x33\x34\x35\x36\x37\x38\x39\x7A\x7A\x66";
        assert_eq!(patch, expected);
    }

    #[test]
    fn test_patch() {
        let source = b"abc013479zz";
        let patch = b"\x03\x00\x00\x00\x00\x00\x00\x00\x0B\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x32\x33\x34\x35\x36\x37\x38\x39\x7A\x7A\x66";
        let target = BsdiffRawDiffer::patch(source, patch).unwrap();
        let expected = b"abc23456789zzf";
        assert_eq!(target, expected);
    }
}