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