1 use std::env;
2 use std::fs::File;
3 use std::io::{self, Write};
4 use std::path::{Path, PathBuf};
5 
6 const CASTAGNOLI_POLY: u32 = 0x82f63b78;
7 
8 type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
9 
main()10 fn main() {
11     if let Err(err) = try_main() {
12         panic!("{}", err);
13     }
14 }
15 
try_main() -> Result<()>16 fn try_main() -> Result<()> {
17     let out_dir = match env::var_os("OUT_DIR") {
18         None => {
19             return Err(From::from("OUT_DIR environment variable not defined"))
20         }
21         Some(out_dir) => PathBuf::from(out_dir),
22     };
23     write_tag_lookup_table(&out_dir)?;
24     write_crc_tables(&out_dir)?;
25     Ok(())
26 }
27 
write_tag_lookup_table(out_dir: &Path) -> Result<()>28 fn write_tag_lookup_table(out_dir: &Path) -> Result<()> {
29     let out_path = out_dir.join("tag.rs");
30     let mut out = io::BufWriter::new(File::create(out_path)?);
31 
32     writeln!(out, "pub const TAG_LOOKUP_TABLE: [u16; 256] = [")?;
33     for b in 0u8..=255 {
34         writeln!(out, "    {},", tag_entry(b))?;
35     }
36     writeln!(out, "];")?;
37     Ok(())
38 }
39 
tag_entry(b: u8) -> u1640 fn tag_entry(b: u8) -> u16 {
41     let b = b as u16;
42     match b & 0b00000011 {
43         0b00 => {
44             let lit_len = (b >> 2) + 1;
45             if lit_len <= 60 {
46                 lit_len
47             } else {
48                 assert!(lit_len <= 64);
49                 (lit_len - 60) << 11
50             }
51         }
52         0b01 => {
53             let len = 4 + ((b >> 2) & 0b111);
54             let offset = (b >> 5) & 0b111;
55             (1 << 11) | (offset << 8) | len
56         }
57         0b10 => {
58             let len = 1 + (b >> 2);
59             (2 << 11) | len
60         }
61         0b11 => {
62             let len = 1 + (b >> 2);
63             (4 << 11) | len
64         }
65         _ => unreachable!(),
66     }
67 }
68 
write_crc_tables(out_dir: &Path) -> Result<()>69 fn write_crc_tables(out_dir: &Path) -> Result<()> {
70     let out_path = out_dir.join("crc32_table.rs");
71     let mut out = io::BufWriter::new(File::create(out_path)?);
72 
73     let table = make_table(CASTAGNOLI_POLY);
74     let table16 = make_table16(CASTAGNOLI_POLY);
75 
76     writeln!(out, "pub const TABLE: [u32; 256] = [")?;
77     for &x in table.iter() {
78         writeln!(out, "    {},", x)?;
79     }
80     writeln!(out, "];\n")?;
81 
82     writeln!(out, "pub const TABLE16: [[u32; 256]; 16] = [")?;
83     for table in table16.iter() {
84         writeln!(out, "    [")?;
85         for &x in table.iter() {
86             writeln!(out, "        {},", x)?;
87         }
88         writeln!(out, "    ],")?;
89     }
90     writeln!(out, "];")?;
91 
92     out.flush()?;
93 
94     Ok(())
95 }
96 
make_table16(poly: u32) -> [[u32; 256]; 16]97 fn make_table16(poly: u32) -> [[u32; 256]; 16] {
98     let mut tab = [[0; 256]; 16];
99     tab[0] = make_table(poly);
100     for i in 0..256 {
101         let mut crc = tab[0][i];
102         for j in 1..16 {
103             crc = (crc >> 8) ^ tab[0][crc as u8 as usize];
104             tab[j][i] = crc;
105         }
106     }
107     tab
108 }
109 
make_table(poly: u32) -> [u32; 256]110 fn make_table(poly: u32) -> [u32; 256] {
111     let mut tab = [0; 256];
112     for i in 0u32..256u32 {
113         let mut crc = i;
114         for _ in 0..8 {
115             if crc & 1 == 1 {
116                 crc = (crc >> 1) ^ poly;
117             } else {
118                 crc >>= 1;
119             }
120         }
121         tab[i as usize] = crc;
122     }
123     tab
124 }
125