crc32fix/
lib.rs

1use crc::crc32;
2use failure::{Error, Fail};
3use png::{Decoded, DecodingError, StreamingDecoder};
4use std::fs;
5use std::io::prelude::*;
6use std::mem;
7use std::path::Path;
8
9#[derive(Debug, Fail)]
10pub enum ReadFileError {
11    #[fail(display = "failed to open file: {}", err)]
12    ParseError { err: DecodingError },
13    #[fail(display = "this file has no incorrect crc value")]
14    CorrectCrc,
15}
16
17#[derive(Default)]
18pub struct PngFile {
19    raw_data: Vec<u8>,
20    crc_data: CrcData,
21    crc_val: u32,
22    offset: usize,
23}
24
25impl PngFile {
26    pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
27        let mut ret: PngFile = Default::default();
28        ret.raw_data = fs::read(path)?;
29        let (crc_val, crc_data) = CrcData::from_raw(&ret.raw_data)?;
30        ret.crc_data = crc_data;
31        ret.crc_val = crc_val;
32        ret.offset = 12;
33        Ok(ret)
34    }
35
36    pub fn try_fix(&mut self) -> Option<(u32, u32)> {
37        let ret = self.crc_data.try_fix(self.crc_val);
38        if ret.is_some() {
39            let new_crc_data = self.crc_data.get_bytes();
40            self.raw_data[self.offset..(self.offset + new_crc_data.len())]
41                .clone_from_slice(&new_crc_data);
42        }
43        ret
44    }
45
46    pub fn save<P: AsRef<Path>>(&self, path: P) -> Result<(), Error> {
47        let mut file = fs::File::create(path)?;
48        file.write_all(&self.raw_data)?;
49        Ok(())
50    }
51}
52
53/// 储存用来校验 crc 值的数据和 crc 值本身
54#[derive(Debug, Default)]
55struct CrcData {
56    pub type_str: [u8; 4],
57    pub width: u32,
58    pub height: u32,
59    pub bits: u8,
60    pub color_type: u8,
61    pub compr_method: u8,
62    pub filter_method: u8,
63    pub interlace_method: u8,
64}
65
66impl CrcData {
67    pub fn from_raw(data: &[u8]) -> Result<(u32, Self), ReadFileError> {
68        let mut crcdata: CrcData = Default::default();
69        let mut decoder = StreamingDecoder::new();
70        let mut idx = 0;
71
72        for _ in 0..3 {
73            let (len, decoded) = match decoder.update(&data[idx..]) {
74                Ok(t) => t,
75                Err(DecodingError::CrcMismatch { crc_val, .. }) => {
76                    return Ok((crc_val, crcdata));
77                }
78                Err(e) => return Err(ReadFileError::ParseError { err: e }),
79            };
80
81            match decoded {
82                Decoded::ChunkBegin(_length, type_str) => {
83                    crcdata.type_str.clone_from_slice(&type_str);
84                }
85                Decoded::Header(width, height, bit_depth, color_type, interlaced) => {
86                    crcdata.width = width;
87                    crcdata.height = height;
88                    crcdata.bits = bit_depth as u8;
89                    crcdata.color_type = color_type as u8;
90                    crcdata.interlace_method = interlaced as u8;
91                }
92                _ => (),
93            }
94            idx += len;
95        }
96        Err(ReadFileError::CorrectCrc)
97    }
98
99    /// 将 CrcData 转化为字节数组
100    #[inline]
101    pub fn get_bytes(&self) -> Vec<u8> {
102        let mut bytes = vec![];
103        let bwidth: [u8; 4] = unsafe { mem::transmute(self.width) };
104        let bheight: [u8; 4] = unsafe { mem::transmute(self.height) };
105
106        bytes.extend(self.type_str.iter());
107        bytes.extend(bwidth.iter().rev());
108        bytes.extend(bheight.iter().rev());
109        bytes.extend(
110            [
111                self.bits,
112                self.color_type,
113                self.compr_method,
114                self.filter_method,
115                self.interlace_method,
116            ]
117            .iter(),
118        );
119        bytes
120    }
121
122    /// 爆破 crc32 值
123    pub fn try_fix(&mut self, crc_val: u32) -> Option<(u32, u32)> {
124        let width = self.width;
125
126        for i in 1..8192 {
127            self.width = i;
128            if crc_val == crc32::checksum_ieee(&self.get_bytes()) {
129                return Some((self.width, self.height));
130            }
131        }
132        self.width = width;
133        for i in 1..8192 {
134            self.height = i;
135            if crc_val == crc32::checksum_ieee(&self.get_bytes()) {
136                return Some((self.width, self.height));
137            }
138        }
139        None
140    }
141}