sqlite_encoder/
db.rs

1use sqlite_types::{Db, DbHeader, TextEncoding, MAGIC_STRING};
2use std::io::Write;
3
4type BoxError = Box<dyn std::error::Error + Send + Sync>;
5
6fn write_bytes(writer: &mut Vec<u8>, value: &[u8]) {
7    writer.extend_from_slice(value);
8}
9
10fn write_u16(writer: &mut Vec<u8>, value: u16) {
11    writer.extend(value.to_be_bytes());
12}
13
14fn write_u32(writer: &mut Vec<u8>, value: u32) {
15    writer.extend(value.to_be_bytes());
16}
17
18fn write_byte(writer: &mut Vec<u8>, value: u8) {
19    writer.push(value);
20}
21
22pub fn encode_header(header: &DbHeader) -> Result<Vec<u8>, BoxError> {
23    let mut buff = Vec::new();
24
25    write_header(&mut buff, &header).map_err(|err| format!("failed to encode header: {}", err))?;
26
27    Ok(buff)
28}
29
30pub fn encode(db: &Db) -> Result<Vec<u8>, BoxError> {
31    let mut buff = Vec::new();
32
33    let header_bytes = encode_header(&db.header)?;
34    let mut first_page = db.pages.get(&1).ok_or("missing page 1")?.clone();
35
36    (&mut first_page[0..100])
37        .write(&header_bytes)
38        .map_err(|err| format!("failed to write header: {}", err))?;
39    buff.write(&first_page)
40        .map_err(|err| format!("failed to write first page: {}", err))?;
41
42    for i in 1..db.header.db_size {
43        // Page number are 1 indexed and 1 is the db header
44        let page_number = i + 1;
45
46        if let Some(page) = db.pages.get(&page_number) {
47            write_bytes(&mut buff, page);
48        } else {
49            // The page didn't exists, write an empty one
50            write_bytes(&mut buff, &vec![0u8; db.header.page_size as usize]);
51        }
52    }
53
54    Ok(buff)
55}
56
57fn write_header(writer: &mut Vec<u8>, header: &DbHeader) -> Result<(), BoxError> {
58    let page_size = if header.page_size == 65536 {
59        1u16
60    } else {
61        header.page_size as u16
62    };
63
64    write_bytes(writer, MAGIC_STRING);
65    write_u16(writer, page_size);
66    write_byte(writer, header.file_format_write_version);
67    write_byte(writer, header.file_format_read_version);
68    write_byte(writer, 0);
69    write_byte(writer, header.max_embedded_payload_frac);
70    write_byte(writer, header.min_embedded_payload_frac);
71    write_byte(writer, header.leaf_payload_frac);
72    write_u32(writer, header.file_change_counter);
73    write_u32(writer, header.db_size);
74    write_u32(writer, header.page_num_first_freelist);
75    write_u32(writer, header.page_count_freelist);
76    write_u32(writer, header.schema_cookie);
77    write_u32(writer, header.schema_format_number);
78    write_u32(writer, header.default_page_cache_size);
79    write_u32(writer, header.page_num_largest_root_btree);
80    write_text_encoding(writer, &header.text_encoding)?;
81    write_u32(writer, header.user_version);
82    write_u32(writer, header.vaccum_mode);
83    write_u32(writer, header.app_id);
84    write_bytes(writer, &[0; 20]);
85    write_u32(writer, header.version_valid_for);
86    write_u32(writer, header.sqlite_version);
87
88    Ok(())
89}
90
91fn write_text_encoding(writer: &mut Vec<u8>, enc: &TextEncoding) -> Result<(), BoxError> {
92    use TextEncoding::*;
93
94    let v = match enc {
95        UTF8 => 1,
96        UTF16le => 2,
97        UTF16be => 3,
98    };
99    write_u32(writer, v);
100
101    Ok(())
102}