1use crate::util::{read_u16, read_u32, read_u8};
3use crate::IResult;
4use crate::ParserError;
5use nom::bytes::complete::take;
6use sqlite_types::{Db, DbHeader, TextEncoding, MAGIC_STRING};
7use std::collections::HashMap;
8
9type BoxError = Box<dyn std::error::Error>;
10
11pub fn decode<'a>(input: &'a [u8]) -> Result<Db, BoxError> {
12 match decode_db(input) {
13 Ok((_, db)) => Ok(db),
14 Err(err) => Err(format!("failed to decode: {}", err).into()),
15 }
16}
17
18fn decode_db<'a, 'b>(input: &'a [u8]) -> IResult<&'a [u8], Db> {
19 let mut pages = HashMap::new();
20
21 let (input, input_header) = take(100usize)(input)?;
22 let (_, header) = decode_header_inner(&input_header)?;
23
24 let (input, bytes) = take(header.page_size - 100)(input)?;
26
27 let first_page = [input_header, bytes].concat();
29 pages.insert(1, first_page);
30
31 assert_eq!(
34 input.len(),
35 header.page_size as usize * (header.db_size as usize - 1)
36 );
37
38 let page_count = input.len() / header.page_size as usize;
39 println!("page_count: {}", page_count);
40
41 let mut input = input;
42 for i in 1..=page_count {
43 let ret = take(header.page_size)(input)?;
44 input = ret.0;
45
46 let page_number = i + 1;
48 pages.insert(page_number as u32, ret.1.to_owned());
49 }
50
51 assert_eq!(pages.len(), header.db_size as usize);
52 Ok((input, Db { header, pages }))
53}
54
55pub fn decode_header(input: &[u8]) -> Result<DbHeader, BoxError> {
56 match decode_header_inner(input) {
57 Ok((_, header)) => Ok(header),
58 Err(err) => Err(format!("failed to decode: {}", err).into()),
59 }
60}
61
62fn decode_text_encoding(input: &[u8]) -> IResult<&[u8], TextEncoding> {
63 let (input, t) = read_u32(input)?;
64
65 use TextEncoding::*;
66 let enc = match t {
67 1 => UTF8,
68 2 => UTF16le,
69 3 => UTF16be,
70 e => {
71 return Err(nom::Err::Failure(ParserError(format!(
72 "unsupported text encoding: {}",
73 e
74 ))))
75 }
76 };
77
78 Ok((input, enc))
79}
80
81fn decode_header_inner(input: &[u8]) -> IResult<&[u8], DbHeader> {
82 let (input, magic_string) = take(16usize)(input)?;
83 if magic_string != MAGIC_STRING {
84 return Err(nom::Err::Failure(ParserError(format!(
85 "magic string not found, got: {:?}",
86 magic_string
87 ))));
88 }
89
90 let (input, page_size) = read_u16(input)?;
91 let (input, file_format_write_version) = read_u8(input)?;
92 let (input, file_format_read_version) = read_u8(input)?;
93 let (input, _reserved) = take(1usize)(input)?;
94 let (input, max_embedded_payload_frac) = read_u8(input)?;
95 let (input, min_embedded_payload_frac) = read_u8(input)?;
96 let (input, leaf_payload_frac) = read_u8(input)?;
97 let (input, file_change_counter) = read_u32(input)?;
98 let (input, db_size) = read_u32(input)?;
99 let (input, page_num_first_freelist) = read_u32(input)?;
100 let (input, page_count_freelist) = read_u32(input)?;
101 let (input, schema_cookie) = read_u32(input)?;
102 let (input, schema_format_number) = read_u32(input)?;
103 let (input, default_page_cache_size) = read_u32(input)?;
104 let (input, page_num_largest_root_btree) = read_u32(input)?;
105 let (input, text_encoding) = decode_text_encoding(input)?;
106 let (input, user_version) = read_u32(input)?;
107 let (input, vaccum_mode) = read_u32(input)?;
108 let (input, app_id) = read_u32(input)?;
109 let (input, _reserved) = take(20usize)(input)?;
110 let (input, version_valid_for) = read_u32(input)?;
111 let (input, sqlite_version) = read_u32(input)?;
112
113 let page_size = if page_size == 1 {
114 65536
115 } else {
116 page_size as u32
117 };
118
119 Ok((
120 input,
121 DbHeader {
122 page_size,
123 file_format_write_version,
124 file_format_read_version,
125 max_embedded_payload_frac,
126 min_embedded_payload_frac,
127 leaf_payload_frac,
128 file_change_counter,
129 db_size,
130 page_num_first_freelist,
131 page_count_freelist,
132 schema_cookie,
133 schema_format_number,
134 default_page_cache_size,
135 page_num_largest_root_btree,
136 text_encoding,
137 user_version,
138 vaccum_mode,
139 app_id,
140 version_valid_for,
141 sqlite_version,
142 },
143 ))
144}