1use std::convert::From;
2use std::error::Error;
3use std::fs::{self, File};
4use std::io::{self, BufRead, BufReader};
5use std::mem;
6use std::path::Path;
7
8use byteorder::{NativeEndian as NE, ReadBytesExt, WriteBytesExt};
9use encoding_rs::*;
10#[cfg(feature = "zip")]
11use zip::ZipArchive;
12#[cfg(feature = "zip")]
13use std::io::{Cursor, Read};
14
15use crate::dictionary::build::*;
16use crate::Utf16Char;
17
18pub trait InputUtil: io::Read {
19 fn get_int(&mut self) -> io::Result<i32> {
20 self.read_i32::<NE>()
21 }
22
23 fn get_int_array(&mut self, count: usize) -> io::Result<Box<[i32]>> {
24 let mut v = vec![0i32; count];
25 for i in 0..count {
26 v[i] = self.read_i32::<NE>()?;
27 }
28 Ok(v.into_boxed_slice())
29 }
30
31 fn get_short_array(&mut self, count: usize) -> io::Result<Box<[i16]>> {
32 let mut v = vec![0i16; count];
33 for i in 0..count {
34 v[i] = self.read_i16::<NE>()?;
35 }
36 Ok(v.into_boxed_slice())
37 }
38
39 fn get_char_array(&mut self, count: usize) -> io::Result<Box<[Utf16Char]>> {
40 let mut v = vec![0u16; count];
41 for i in 0..count {
42 v[i] = self.read_u16::<NE>()?;
43 }
44 Ok(v.into_boxed_slice())
45 }
46
47 fn get_string(&mut self, count: usize) -> io::Result<Box<[Utf16Char]>> {
48 let mut v = vec![0u16; count];
49 for i in 0..count {
50 v[i] = self.read_u16::<NE>()?;
51 }
52 Ok(v.into_boxed_slice())
53 }
54}
55
56impl<R: io::Read + ?Sized> InputUtil for R {}
57
58
59pub fn read_all_as_chars(dir: &mut dyn DirLike, path: &str) -> io::Result<Box<[Utf16Char]>> {
60 let file_len = dir.file_size(path)?;
61 let file = dir.open(path)?;
62 let mut reader = BufReader::new(file);
63 reader.get_string((file_len as usize) / mem::size_of::<u16>())
64}
65
66pub fn read_all_as_int_array(dir: &mut dyn DirLike, path: &str) -> io::Result<Box<[i32]>> {
67 let file_len = dir.file_size(path)?;
68 let file = dir.open(path)?;
69 let mut reader = BufReader::new(file);
70 reader.get_int_array((file_len as usize) / mem::size_of::<i32>())
71}
72
73
74pub trait OutputUtil: io::Write {
75 fn put_string(&mut self, str: &[Utf16Char]) -> io::Result<()> {
76 for i in 0..str.len() {
77 self.write_u16::<NE>(str[i])?;
78 }
79 Ok(())
80 }
81}
82
83impl<W: io::Write + ?Sized> OutputUtil for W {}
84
85
86pub struct ReadLine<'a> {
87 reader: BufReader<File>,
88 line_number: i32,
89 path: &'a Path,
90 decoder: Option<&'static Encoding>,
91 encoded_buf: Vec<u8>,
92}
93
94impl<'a> ReadLine<'a> {
95 pub fn new(file_path: &'a Path, encoding_name: &str) -> AppResult<ReadLine<'a>> {
96 let file = File::open(file_path)?;
97 let encoding = Encoding::for_label(encoding_name.as_bytes())
98 .ok_or_else(|| format!("Unknown encoding; {}", encoding_name))?;
99
100Ok(ReadLine {
102 reader: BufReader::new(file),
103 line_number: 0,
104 path: file_path,
105 decoder: if encoding != UTF_8 { Some(encoding) } else { None },
106 encoded_buf: Vec::new(),
107 })
108 }
109
110 pub fn next(&mut self, read_buf: &mut String) -> AppResult<usize> {
111 match self.decoder {
112 Some(encoding) =>
113 self.next_with_decoder(encoding.new_decoder_without_bom_handling(), read_buf),
114 None => self.next_without_decoder(read_buf)
115 }
116 }
117
118 fn next_without_decoder(&mut self, read_buf: &mut String) -> AppResult<usize> {
119 read_buf.clear();
120 let r = self.reader.read_line(read_buf);
121 if r.as_ref().map(|len| *len > 0).unwrap_or(false) {
122 self.line_number += 1;
123 }
124 r.map_err(AppError::from)
125 }
126
127 fn next_with_decoder(&mut self, mut decoder: Decoder, decode_buf: &mut String) -> AppResult<usize> {
128 self.encoded_buf.clear();
129 decode_buf.clear();
130 let len = self.reader.read_until(b'\n', self.encoded_buf.as_mut()).map_err(AppError::from)?;
131 if len < 1 {
132 Ok(0) } else {
134 decode_buf.reserve(decoder.max_utf8_buffer_length_without_replacement(len).expect("overflow"));
135 let (result, _) =
136 decoder.decode_to_string_without_replacement(&self.encoded_buf, decode_buf, true);
137 match result {
138 DecoderResult::InputEmpty => {
139 self.line_number += 1;
140 Ok(decode_buf.len())
141 }
142 DecoderResult::Malformed(_, _) => Err(AppError::from("Decoder Malformed")),
143 DecoderResult::OutputFull => Err(AppError::from("Decoder OutputFull"))
144 }
145 }
146 }
147
148 pub fn parse_error<S: Into<String>>(&self, msg: S) -> AppError {
149 AppError::Parse {
150 message: msg.into(),
151 path: self.path.to_path_buf(),
152 line_number: self.line_number,
153 }
154 }
155
156 pub fn convert_error<E: Error>(&self, e: E) -> AppError {
157 self.parse_error(e.description())
158 }
159}
160
161pub trait DirLike {
165 fn file_size(&mut self, path: &str) -> io::Result<u64>;
167 fn open(&mut self, path: &str) -> io::Result<Box<dyn io::Read>>;
169}
170
171#[cfg(feature = "zip")]
173pub struct ZipDir<R: io::Read + io::Seek>(ZipArchive<R>);
174
175#[cfg(feature = "zip")]
176impl<R: io::Read + io::Seek> DirLike for ZipDir<R> {
177 fn file_size(&mut self, path: &str) -> io::Result<u64> {
178 Ok(self.0.by_name(path)?.size())
179 }
180
181 fn open(&mut self, path: &str) -> io::Result<Box<dyn io::Read>> {
182 let mut file = self.0.by_name(path)?;
183 let mut buf = Vec::with_capacity(file.size() as usize);
184 file.read_to_end(&mut buf)?;
185 Ok(Box::new(Cursor::new(buf)))
186 }
187}
188
189#[cfg(feature = "zip")]
190impl<R: io::Read + io::Seek> ZipDir<R> {
191 pub fn new(buf: R) -> io::Result<ZipDir<R>> {
195 Ok(ZipDir(ZipArchive::new(buf)?))
196 }
197}
198
199impl DirLike for &Path {
201 fn file_size(&mut self, path: &str) -> io::Result<u64> {
202 let buf = self.join(path);
203 Ok(fs::metadata(buf)?.len())
204 }
205
206 fn open(&mut self, path: &str) -> io::Result<Box<dyn io::Read>> {
207 let buf = self.join(path);
208 File::open(buf).map(|f| Box::new(f) as Box<dyn io::Read>)
209 }
210}
211
212#[allow(dead_code)]
213pub mod debug {
214 use std::fs::File;
215 use std::io::Write;
216
217 pub fn dump_string_list(list: &[String], path: &str) {
218 let mut f = File::create(path).unwrap();
219 for s in list {
220 f.write_all(s.as_bytes()).unwrap();
221 f.write_all(b"\n").unwrap();
222 }
223 }
224}