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 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 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}