1use std::collections::{HashMap, VecDeque, hash_map::Entry};
2use std::error::Error as StdError;
3use std::fmt;
4use std::hint::cold_path;
5use std::ops::Range;
6use std::str::from_utf8;
7
8use memchr::{memchr, memmem::find};
9
10pub struct Database<C> {
11 cache: C,
12 types: Box<[FrozenType]>,
13 matches: FrozenMatches,
14 children: FrozenChildren,
15 text_idx: u32,
16 binary_idx: u32,
17}
18
19#[derive(Debug, Default)]
20struct Type {
21 matches: Vec<Match>,
22 children: Vec<u32>,
23}
24
25#[derive(Debug)]
26struct Match {
27 cnt: u32,
28 off: u32,
29}
30
31#[derive(Debug)]
32struct FrozenType {
33 mime_type_off: u32,
34 matches: Range<u32>,
35 children: Range<u32>,
36}
37
38type FrozenMatches = Box<[Match]>;
39
40type FrozenChildren = Box<[u32]>;
41
42impl<C> Database<C>
43where
44 C: AsRef<[u8]>,
45{
46 #[cold]
63 pub fn open(cache: C) -> Result<Self, Error> {
64 let (parents, types) = parse_offsets(cache.as_ref()).bail(Error::MalformedOffsets)?;
65
66 let mut parents = parse_parents(cache.as_ref(), parents).bail(Error::MalformedParents)?;
67
68 let mut types = parse_types(cache.as_ref(), types).bail(Error::MalformedTypes)?;
69
70 let (text_off, binary_off) = parents_to_children(cache.as_ref(), &mut parents, &mut types)?;
71
72 let types = sort(types, parents)?;
73
74 Ok(Self::freeze(cache, types, text_off, binary_off))
75 }
76
77 fn freeze(cache: C, types: Vec<(u32, Type)>, text_off: u32, binary_off: u32) -> Self {
78 let mut matches =
79 Vec::with_capacity(types.iter().map(|(_, r#type)| r#type.matches.len()).sum());
80 let mut children =
81 Vec::with_capacity(types.iter().map(|(_, r#type)| r#type.children.len()).sum());
82
83 let types = types
84 .into_iter()
85 .map(|(mime_type_off, r#type)| {
86 let matches_start = u32::try_from(matches.len()).unwrap();
87 let matches_len = u32::try_from(r#type.matches.len()).unwrap();
88 let matches_end = matches_start.checked_add(matches_len).unwrap();
89 matches.extend(r#type.matches);
90
91 let children_start = u32::try_from(children.len()).unwrap();
92 let children_len = u32::try_from(r#type.children.len()).unwrap();
93 let children_end = children_start.checked_add(children_len).unwrap();
94 children.extend(r#type.children);
95
96 FrozenType {
97 mime_type_off,
98 matches: matches_start..matches_end,
99 children: children_start..children_end,
100 }
101 })
102 .collect::<Box<[_]>>();
103
104 let mime_type_off_to_type_idx = types
105 .iter()
106 .enumerate()
107 .map(|(idx, r#type)| (r#type.mime_type_off, u32::try_from(idx).unwrap()))
108 .collect::<HashMap<_, _>>();
109
110 for type_idx in &mut children {
111 *type_idx = mime_type_off_to_type_idx[type_idx];
112 }
113
114 Self {
115 cache,
116 types,
117 matches: matches.into(),
118 children: children.into(),
119 text_idx: mime_type_off_to_type_idx[&text_off],
120 binary_idx: mime_type_off_to_type_idx[&binary_off],
121 }
122 }
123
124 pub fn r#match<'a>(&'a self, bytes: &[u8]) -> Result<&'a str, Error> {
125 let is_text = memchr(0, bytes).is_none();
126
127 let text_type = &self.types[self.text_idx as usize];
128 let binary_type = &self.types[self.binary_idx as usize];
129
130 let mime_type_off = if is_text
131 && let Some(mime_type_off) = self.match_children(None, &text_type.children, bytes)?
132 {
133 mime_type_off
134 } else if let Some(mime_type_off) =
135 self.match_children(None, &binary_type.children, bytes)?
136 {
137 mime_type_off
138 } else if is_text {
139 text_type.mime_type_off
140 } else {
141 binary_type.mime_type_off
142 };
143
144 resolve_mime_type(self.cache.as_ref(), mime_type_off).bail(Error::InvalidMimeType)
145 }
146
147 fn match_children(
148 &self,
149 default: Option<u32>,
150 children: &Range<u32>,
151 bytes: &[u8],
152 ) -> Result<Option<u32>, Error> {
153 let children = &self.children[children.start as usize..children.end as usize];
154
155 for type_idx in children {
156 let r#type = &self.types[*type_idx as usize];
157
158 let matches = &self.matches[r#type.matches.start as usize..r#type.matches.end as usize];
159
160 for r#match in matches {
161 if try_match(self.cache.as_ref(), 0, r#match.cnt, r#match.off, bytes)
162 .bail(Error::MalformedMatch)?
163 {
164 return self.match_children(
165 Some(r#type.mime_type_off),
166 &r#type.children,
167 bytes,
168 );
169 }
170 }
171 }
172
173 Ok(default)
174 }
175}
176
177fn try_match(cache: &[u8], depth: u8, cnt: u32, off: u32, bytes: &[u8]) -> Option<bool> {
178 if depth == 128 {
179 return None;
180 }
181
182 let cnt = cnt as usize;
183 let off = off as usize;
184
185 let matchlets = cache.get(off..)?.get(..32 * cnt)?;
186
187 for idx in 0..cnt {
188 let matchlet = &matchlets[32 * idx..][..32];
189
190 if try_matchlet(cache, matchlet, bytes)? {
191 let cnt = parse_u32(matchlet, 24);
192 let off = parse_u32(matchlet, 28);
193
194 if cnt == 0 || try_match(cache, depth + 1, cnt, off, bytes)? {
195 return Some(true);
196 }
197 }
198 }
199
200 Some(false)
201}
202
203#[inline]
204fn try_matchlet(cache: &[u8], matchlet: &[u8], bytes: &[u8]) -> Option<bool> {
205 let range_start = parse_u32(matchlet, 0) as usize;
206 let range_length = parse_u32(matchlet, 4) as usize;
207 let data_length = parse_u32(matchlet, 12) as usize;
208 let data_offset = parse_u32(matchlet, 16) as usize;
209 let mask_offset = parse_u32(matchlet, 20) as usize;
210
211 let data = cache.get(data_offset..)?.get(..data_length)?;
212
213 let mask = if mask_offset != 0 {
214 Some(cache.get(mask_offset..)?.get(..data_length)?)
215 } else {
216 None
217 };
218
219 for pos in range_start..range_start + range_length {
220 if let Some(bytes) = bytes.get(pos..pos + data_length) {
221 if let Some(mask) = mask {
222 if data
223 .iter()
224 .zip(mask)
225 .zip(bytes)
226 .all(|((data, mask), byte)| data & mask == byte & mask)
227 {
228 return Some(true);
229 }
230 } else {
231 if compare(data, bytes) {
232 return Some(true);
233 }
234 }
235 } else {
236 break;
237 }
238 }
239
240 Some(false)
241}
242
243#[inline]
244fn compare(lhs: &[u8], rhs: &[u8]) -> bool {
245 let len = lhs.len();
246 debug_assert_eq!(len, rhs.len());
247
248 if len >= 8 {
249 let lhs_lo = u64::from_le_bytes(lhs[..8].try_into().unwrap());
250 let rhs_lo = u64::from_le_bytes(rhs[..8].try_into().unwrap());
251 if lhs_lo != rhs_lo {
252 return false;
253 } else if len == 8 {
254 return true;
255 }
256
257 let lhs_hi = u64::from_le_bytes(lhs[len - 8..].try_into().unwrap());
258 let rhs_hi = u64::from_le_bytes(rhs[len - 8..].try_into().unwrap());
259 if lhs_hi != rhs_hi {
260 return false;
261 } else if len <= 16 {
262 return true;
263 }
264 } else if len >= 4 {
265 let lhs_lo = u32::from_le_bytes(lhs[..4].try_into().unwrap());
266 let rhs_lo = u32::from_le_bytes(rhs[..4].try_into().unwrap());
267 if lhs_lo != rhs_lo {
268 return false;
269 }
270
271 let lhs_hi = u32::from_le_bytes(lhs[len - 4..].try_into().unwrap());
272 let rhs_hi = u32::from_le_bytes(rhs[len - 4..].try_into().unwrap());
273 return lhs_hi == rhs_hi;
274 } else if len > 0 {
275 let lhs_lo = lhs[0];
276 let rhs_lo = rhs[0];
277 if lhs_lo != rhs_lo {
278 return false;
279 }
280
281 let lhs_mid = lhs[len / 2];
282 let rhs_mid = rhs[len / 2];
283 if lhs_mid != rhs_mid {
284 return false;
285 }
286
287 let lhs_hi = lhs[len - 1];
288 let rhs_hi = rhs[len - 1];
289 return lhs_hi == rhs_hi;
290 } else {
291 return true;
292 }
293
294 lhs == rhs
295}
296
297fn sort(
298 mut types: HashMap<u32, Type>,
299 mut parents: HashMap<u32, Vec<u32>>,
300) -> Result<Vec<(u32, Type)>, Error> {
301 let mut sorted = Vec::with_capacity(types.len());
302
303 let mut orphans = types
304 .keys()
305 .copied()
306 .filter(|mime_type_off| !parents.contains_key(mime_type_off))
307 .collect::<VecDeque<_>>();
308
309 while let Some(orphan_mime_type_off) = orphans.pop_back() {
310 let orphan_type = types.remove(&orphan_mime_type_off).unwrap();
311
312 for child_mime_type_off in &orphan_type.children {
313 match parents.entry(*child_mime_type_off) {
314 Entry::Occupied(mut entry) => {
315 let parents = entry.get_mut();
316
317 parents.retain(|parent_mime_type_off| {
318 *parent_mime_type_off != orphan_mime_type_off
319 });
320
321 if parents.is_empty() {
322 entry.remove();
323
324 orphans.push_front(*child_mime_type_off);
325 }
326 }
327 Entry::Vacant(_) => unreachable!(),
328 }
329 }
330
331 sorted.push((orphan_mime_type_off, orphan_type));
332 }
333
334 if parents.is_empty() {
335 Ok(sorted)
336 } else {
337 Err(Error::MalformedParents)
338 }
339}
340
341fn parents_to_children(
342 cache: &[u8],
343 parents: &mut HashMap<u32, Vec<u32>>,
344 types: &mut HashMap<u32, Type>,
345) -> Result<(u32, u32), Error> {
346 types.retain(|mime_type_off, _type| resolve_mime_type(cache, *mime_type_off).is_some());
347
348 parents.retain(|mime_type_off, parents| {
349 if types.contains_key(mime_type_off) {
350 parents.retain(|parent_mime_type_off| types.contains_key(parent_mime_type_off));
351
352 !parents.is_empty()
353 } else {
354 false
355 }
356 });
357
358 let text_off =
359 find_or_insert_mime_type(cache, types, "text/plain\0").bail(Error::MissingTextPlain)?;
360
361 let binary_off = find_or_insert_mime_type(cache, types, "application/octet-stream\0")
362 .bail(Error::MissingApplicationOctetStream)?;
363
364 for mime_type_off in types.keys() {
365 if *mime_type_off != text_off
366 && *mime_type_off != binary_off
367 && let Entry::Vacant(entry) = parents.entry(*mime_type_off)
368 {
369 let mime_type = resolve_mime_type(cache, *mime_type_off).unwrap();
370
371 let parent_mime_type_off = if mime_type.starts_with("text/") {
372 text_off
373 } else {
374 binary_off
375 };
376
377 entry.insert(vec![parent_mime_type_off]);
378 }
379 }
380
381 for (mime_type_off, parents) in parents {
382 for parent_mime_type_off in parents {
383 types
384 .get_mut(parent_mime_type_off)
385 .unwrap()
386 .children
387 .push(*mime_type_off);
388 }
389 }
390
391 for r#type in types.values_mut() {
392 r#type.children.sort_unstable();
393 r#type.children.dedup();
394 }
395
396 Ok((text_off, binary_off))
397}
398
399fn find_or_insert_mime_type(
400 cache: &[u8],
401 types: &mut HashMap<u32, Type>,
402 mime_type0: &str,
403) -> Option<u32> {
404 let mime_type = &mime_type0[..mime_type0.len() - 1];
405
406 let mime_type_off = types
407 .keys()
408 .copied()
409 .find(|mime_type_off| resolve_mime_type(cache, *mime_type_off) == Some(mime_type));
410
411 mime_type_off.or_else(|| {
412 let mime_type_off = find(cache, mime_type0.as_bytes())?.try_into().ok()?;
413
414 types.insert(mime_type_off, Default::default());
415
416 Some(mime_type_off)
417 })
418}
419
420fn resolve_mime_type(cache: &[u8], mime_type_off: u32) -> Option<&str> {
421 let off = mime_type_off as usize;
422 let bytes = cache.get(off..)?;
423
424 let pos = memchr(0, bytes)?;
425 let mime_type = &bytes[..pos];
426
427 from_utf8(mime_type).ok()
428}
429
430fn parse_offsets(cache: &[u8]) -> Option<(&[u8], &[u8])> {
431 if cache.len() < 2 * 2 + 9 * 4 {
432 return None;
433 }
434
435 let parents_off = parse_u32(cache, 2 * 2 + 4) as usize;
436 let types_off = parse_u32(cache, 2 * 2 + 5 * 4) as usize;
437
438 let parents = cache.get(parents_off..)?;
439 let types = cache.get(types_off..)?;
440
441 Some((parents, types))
442}
443
444fn parse_parents<'a>(cache: &'a [u8], bytes: &'a [u8]) -> Option<HashMap<u32, Vec<u32>>> {
445 if bytes.len() < 4 {
446 return None;
447 }
448
449 let cnt = parse_u32(bytes, 0) as usize;
450
451 let bytes = bytes.get(4..)?.get(..8 * cnt)?;
452
453 let mut parents = HashMap::<_, Vec<_>>::with_capacity(cnt);
454
455 for idx in 0..cnt {
456 let bytes = &bytes[8 * idx..][..8];
457
458 let mime_type_off = parse_u32(bytes, 0);
459 let parents_off = parse_u32(bytes, 4) as usize;
460
461 let bytes = cache.get(parents_off..)?;
462
463 if bytes.len() < 4 {
464 return None;
465 }
466
467 let cnt = parse_u32(bytes, 0) as usize;
468
469 let bytes = bytes.get(4..)?.get(..4 * cnt)?;
470
471 let parents = parents.entry(mime_type_off).or_default();
472 parents.reserve(cnt);
473
474 for idx in 0..cnt {
475 let parent_mime_type_off = parse_u32(bytes, 4 * idx);
476
477 parents.push(parent_mime_type_off);
478 }
479 }
480
481 Some(parents)
482}
483
484fn parse_types(cache: &[u8], bytes: &[u8]) -> Option<HashMap<u32, Type>> {
485 if bytes.len() < 3 * 4 {
486 return None;
487 }
488
489 let cnt = parse_u32(bytes, 0) as usize;
490 let off = parse_u32(bytes, 8) as usize;
491
492 let bytes = cache.get(off..)?.get(..16 * cnt)?;
493
494 let mut types = HashMap::<_, Type>::with_capacity(cnt);
495
496 for idx in 0..cnt {
497 let bytes = &bytes[16 * idx..];
498
499 let mime_type_off = parse_u32(bytes, 4);
500
501 let cnt = parse_u32(bytes, 8);
502 let off = parse_u32(bytes, 12);
503
504 types
505 .entry(mime_type_off)
506 .or_default()
507 .matches
508 .push(Match { cnt, off });
509 }
510
511 Some(types)
512}
513
514fn parse_u32(bytes: &[u8], off: usize) -> u32 {
515 u32::from_be_bytes(bytes[off..][..4].try_into().unwrap())
516}
517
518#[derive(Debug, Clone, Copy)]
519pub enum Error {
520 MalformedOffsets,
521 MalformedParents,
522 MalformedTypes,
523 MalformedMatch,
524 MissingTextPlain,
525 MissingApplicationOctetStream,
526 InvalidMimeType,
527}
528
529trait BailExt<T> {
530 fn bail(self, err: Error) -> Result<T, Error>;
531}
532
533impl<T> BailExt<T> for Option<T> {
534 #[inline(always)]
535 fn bail(self, err: Error) -> Result<T, Error> {
536 self.ok_or_else(|| {
537 cold_path();
538 err
539 })
540 }
541}
542
543impl fmt::Display for Error {
544 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
545 let msg = match self {
546 Self::MalformedOffsets => "Malformed offsets",
547 Self::MalformedParents => "Malformed parents",
548 Self::MalformedTypes => "Malformed types",
549 Self::MalformedMatch => "Malformed match",
550 Self::MissingTextPlain => "Missing text/plain MIME type",
551 Self::MissingApplicationOctetStream => "Missing application/octet-stream MIME type",
552 Self::InvalidMimeType => "Invalid MIME type",
553 };
554
555 fmt.write_str(msg)
556 }
557}
558
559impl StdError for Error {}