serde_gff/parser/mod.rs
1//! Реализация потокового парсера GFF файла. См. описание структуры [`Parser`](struct.Parser.html)
2
3use std::iter::FusedIterator;
4use std::io::{Read, Seek, SeekFrom};
5use byteorder::{LE, ReadBytesExt};
6use encoding::{EncodingRef, DecoderTrap};
7use encoding::all::UTF_8;
8
9use crate::{Label, SubString, ResRef, StrRef};
10use crate::error::{Error, Result};
11use crate::header::Header;
12use crate::index::{Index, LabelIndex, U64Index, I64Index, F64Index, StringIndex, ResRefIndex, LocStringIndex, BinaryIndex};
13use crate::string::{LocString, StringKey};
14use crate::value::{SimpleValue, SimpleValueRef};
15
16mod token;
17mod states;
18
19use self::states::State;
20pub use self::token::Token;
21
22/// Уникальный идентификатор типа структуры, хранимой в GFF-файле
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24pub struct Tag(u32);
25
26/// Реализует потоковый (наподобие SAX) парсер GFF файла. Парсер реализует интерфейс
27/// итератора по [токенам]. Каждый вызов метода [`next_token`] возвращает следующий токен
28/// из потока, который сразу же может быть использован для анализа или сохранен для
29/// дальнейшего использования.
30///
31/// # События разбора
32/// Парсер представляет собой pull-down парсер, т.е. для получения данных его нужно опрашивать внешним
33/// циклом (в противоположность push-down парсеру, который испускает события при разборе очередного
34/// элемента).
35///
36/// Так как GFF файл может быть представлен в XML виде, и эта структура проще для представления в тексте,
37/// то ниже показан пример файла, в котором отмечены места после которых парсер генерирует токены при
38/// разборе. В виде кода Rust описанная структура данных может быть представлена таким образом:
39///
40/// ```rust,no_run
41/// struct Struct;
42/// struct Item {
43/// double: f64,
44/// }
45/// struct Root {
46/// int: i32,
47/// struc: Struct,
48/// list: Vec<Item>,
49/// }
50/// ```
51/// XML представление:
52/// ```xml
53/// <STRUCT tag='4294967295'>[1]
54/// <FIELD label='int'[2] type='INT'>8</FIELD>[3]
55/// <FIELD label='struc'[4] type='STRUCT'>
56/// <STRUCT tag='1'>[5]
57/// </STRUCT>[6]
58/// </FIELD>
59/// <FIELD label='list'[7] type='LIST'>[8]
60/// <STRUCT tag='2'>[9]
61/// <FIELD label='double'[10] type='DOUBLE'>0.000000</FIELD>[11]
62/// </STRUCT>[12]
63/// </FIELD>[13]
64/// </STRUCT>[14]
65/// ```
66/// Токены, получаемые последовательным вызовом [`next_token`]:
67/// 1. [`RootBegin`]. Прочитано описание корневой структуры -- в этом состоянии уже известен
68/// тег типа структуры и количество полей в ней.
69/// 2. [`Label`]. Прочитан индекс метки, по этому индексу может быть прочитано значение метки
70/// 3. [`Value`]. Прочитано примитивное значение
71/// 4. [`Label`]. Прочитан индекс метки, по этому индексу может быть прочитано значение метки
72/// 5. [`StructBegin`]. Прочитано количество полей структуры и ее тег
73/// 6. [`StructEnd`]
74/// 7. [`Label`]. Прочитан индекс метки, по этому индексу может быть прочитано значение метки
75/// 8. [`ListBegin`]. Прочитано количество элементов списка
76/// 9. [`ItemBegin`]. Прочитано количество полей структуры, ее тег, а также предоставляется
77/// информация о порядковом индексе элемента
78/// 10. [`Label`]. Прочитан индекс метки, по этому индексу может быть прочитано значение метки
79/// 11. [`Value`]. Прочитан индекс большого значения (больше 4-х байт), по этому индексу само
80/// значение может быть прочитано отдельным вызовом
81/// 12. [`ItemEnd`]. Элемент списка прочитан
82/// 13. [`ListEnd`]. Весь список прочитан
83/// 14. [`RootEnd`]. Файл прочитан
84///
85/// # Пример
86/// В данном примере читается файл с диска, и в потоковом режиме выводится на экран, формируя
87/// что-то, напоминающее JSON.
88///
89/// ```rust
90/// use std::fs::File;
91/// use serde_gff::parser::Parser;
92/// use serde_gff::parser::Token::*;
93///
94/// // Читаем файл с диска и создаем парсер. При создании парсер сразу же читает небольшую
95/// // порцию данных -- заголовок, которая нужна ему для правильного разрешения ссылок
96/// let file = File::open("test-data/all.gff").expect("test file not exist");
97/// let mut parser = Parser::new(file).expect("reading GFF header failed");
98/// let mut indent = 0;
99/// loop {
100/// // В данном случае мы используем методы типажа Iterator для итерирования по файлу, так
101/// // как мы полагаем, что ошибок в процессе чтения не возникнет. Если же они интересны,
102/// // следует использовать метод `next_token`
103/// if let Some(token) = parser.next() {
104/// match token {
105/// RootBegin {..} | RootEnd => {},
106/// // Обрамляем структуры в `{ ... }`
107/// StructBegin {..} => { indent += 1; println!("{{"); },
108/// StructEnd => { indent -= 1; println!("{:indent$}}}", "", indent=indent*2); },
109/// // Обрамляем списки в `[ ... ]`
110/// ListBegin {..} => { indent += 1; println!("["); },
111/// ListEnd => { indent -= 1; println!("{:indent$}]", "", indent=indent*2); },
112/// // Обрамляем элементы списков в `[index]: { ... }`
113/// ItemBegin { index, .. } => {
114/// println!("{:indent$}[{}]: {{", "", index, indent=indent*2);
115/// indent += 1;
116/// },
117/// ItemEnd => {
118/// indent -= 1;
119/// println!("{:indent$}}}", "", indent=indent*2);
120/// },
121///
122/// Label(index) => {
123/// // Физически значение меток хранится в другом месте файла. Так как при итерировании они
124/// // могут быть нам неинтересны, то токен содержит только индекс используемой метки (имени
125/// // поля). В данном же случае они нас интересуют, поэтому выполняем полное чтение
126/// let label = parser.read_label(index).expect(&format!("can't read label {:?}", index));
127/// print!("{:indent$}{}: ", "", label, indent=indent*2)
128/// },
129///
130/// // Аналогично со значениями. Некоторые значения доступны сразу (те, чей размер не превышает
131/// // 4 байта), другие хранятся с других частях файла и должны быть явно прочитаны.
132/// // Также, если вас интересует только какое-то конкретное значение, может быть использован
133/// // один из методов `read_*` парсера
134/// Value(value) => println!("{:?}", parser.read_value(value).expect("can't read value")),
135/// }
136/// continue;
137/// }
138/// // Как только итератор возвращает None, файл закончился, либо произошла ошибка; завершаем работу
139/// break;
140/// }
141/// ```
142///
143/// [токенам]: enum.Token.html
144/// [`next_token`]: struct.Parser.html#method.next_token
145/// [`RootBegin`]: enum.Token.html#variant.RootBegin
146/// [`RootEnd`]: enum.Token.html#variant.RootEnd
147/// [`StructBegin`]: enum.Token.html#variant.StructBegin
148/// [`StructEnd`]: enum.Token.html#variant.StructEnd
149/// [`ListBegin`]: enum.Token.html#variant.ListBegin
150/// [`ListEnd`]: enum.Token.html#variant.ListEnd
151/// [`ItemBegin`]: enum.Token.html#variant.ItemBegin
152/// [`ItemEnd`]: enum.Token.html#variant.ItemEnd
153/// [`Label`]: enum.Token.html#variant.Label
154/// [`Value`]: enum.Token.html#variant.Value
155pub struct Parser<R: Read + Seek> {
156 /// Источник данных для чтения элементов GFF-файла
157 reader: R,
158 /// Заголовок GFF файла, содержащий информацию о местоположении различных секций файла
159 header: Header,
160 /// Кодировка, используемая для декодирования строк
161 encoding: EncodingRef,
162 /// Способ обработки ошибок декодирования строк
163 trap: DecoderTrap,
164 /// Текущее состояние разбора
165 state: State,
166}
167
168impl<R: Read + Seek> Parser<R> {
169 /// Создает парсер для чтения GFF файла из указанного источника данных с использованием
170 /// кодировки `UTF-8` для декодирования строк и генерацией ошибки в случае, если декодировать
171 /// набор байт, как строку в этой кодировке, не удалось.
172 ///
173 /// # Параметры
174 /// - `reader`: Источник данных для чтения файла
175 pub fn new(reader: R) -> Result<Self> {
176 Self::with_encoding(reader, UTF_8, DecoderTrap::Strict)
177 }
178 /// Создает парсер для чтения GFF файла из указанного источника данных с использованием
179 /// указанной кодировки для декодирования строк.
180 ///
181 /// # Параметры
182 /// - `reader`: Источник данных для чтения файла
183 /// - `encoding`: Кодировка для декодирования символов в строках
184 /// - `trap`: Способ обработки символов в строках, которые не удалось декодировать с
185 /// использованием выбранной кодировки
186 pub fn with_encoding(mut reader: R, encoding: EncodingRef, trap: DecoderTrap) -> Result<Self> {
187 let header = Header::read(&mut reader)?;
188
189 Ok(Parser { header, reader, encoding, trap, state: State::default() })
190 }
191 /// Возвращает следующий токен или ошибку, если данных не осталось или при их чтении возникли
192 /// проблемы.
193 pub fn next_token(&mut self) -> Result<Token> {
194 let (token, next) = self.state.clone().next(self)?;
195 self.state = next;
196 Ok(token)
197 }
198 /// Быстро пропускает всю внутреннюю структуру, переводя парсер в состояние, при котором
199 /// вызов [`next_token`] вернет следующий структурный элемент после пропущенного (следующее
200 /// поле структуры или элемент списка).
201 ///
202 /// # Параметры
203 /// - `token`: Токен, полученный предшествующим вызовом [`next_token`]
204 ///
205 /// [`next_token`]: #method.next_token
206 #[inline]
207 pub fn skip_next(&mut self, token: Token) {
208 self.state = self.state.clone().skip(token);
209 }
210//-------------------------------------------------------------------------------------------------
211// Завершение чтения комплексных данных
212//-------------------------------------------------------------------------------------------------
213 /// Читает из файла значение метки по указанному индексу.
214 /// Не меняет позицию чтения в файле
215 pub fn read_label(&mut self, index: LabelIndex) -> Result<Label> {
216 let old = self.offset()?;
217 self.seek(index)?;
218
219 let mut label = [0u8; 16];
220 self.reader.read_exact(&mut label)?;
221
222 self.reader.seek(old)?;
223 Ok(label.into())
224 }
225 /// Читает из файла значение поля по указанному индексу. Побочный эффект -- переход по указанному адресу
226 pub fn read_u64(&mut self, index: U64Index) -> Result<u64> {
227 self.seek(index)?;
228 self.reader.read_u64::<LE>().map_err(Into::into)
229 }
230 /// Читает из файла значение поля по указанному индексу. Побочный эффект -- переход по указанному адресу
231 pub fn read_i64(&mut self, index: I64Index) -> Result<i64> {
232 self.seek(index)?;
233 self.reader.read_i64::<LE>().map_err(Into::into)
234 }
235 /// Читает из файла значение поля по указанному индексу. Побочный эффект -- переход по указанному адресу
236 pub fn read_f64(&mut self, index: F64Index) -> Result<f64> {
237 self.seek(index)?;
238 self.reader.read_f64::<LE>().map_err(Into::into)
239 }
240 /// Читает 4 байта длины и следующие за ними байты строки, интерпретирует их в соответствии с
241 /// кодировкой декодера и возвращает полученную строку. Побочный эффект -- переход по указанному адресу
242 pub fn read_string(&mut self, index: StringIndex) -> Result<String> {
243 self.seek(index)?;
244 self.read_string_impl()
245 }
246 /// Читает 1 байт длины и следующие за ними байты массива, возвращает прочитанный массив,
247 /// обернутый в `ResRef`. Побочный эффект -- переход по указанному адресу
248 pub fn read_resref(&mut self, index: ResRefIndex) -> Result<ResRef> {
249 self.seek(index)?;
250
251 let size = self.reader.read_u8()? as usize;
252 let mut bytes = Vec::with_capacity(size);
253 unsafe { bytes.set_len(size); }
254
255 self.reader.read_exact(&mut bytes)?;
256 Ok(ResRef(bytes))
257 }
258 /// Читает из файла значение поля по указанному индексу. Побочный эффект -- переход по указанному адресу
259 pub fn read_loc_string(&mut self, index: LocStringIndex) -> Result<LocString> {
260 self.seek(index)?;
261
262 let _total_size = self.read_u32()?;
263 let str_ref = StrRef(self.read_u32()?);
264 let count = self.read_u32()?;
265
266 let mut strings = Vec::with_capacity(count as usize);
267 for _i in 0..count {
268 strings.push(self.read_substring()?);
269 }
270
271 Ok(LocString { str_ref, strings })
272 }
273 /// Читает 4 байта длины и следующие за ними байты массива, возвращает прочитанный массив.
274 /// Побочный эффект -- переход по указанному адресу
275 pub fn read_byte_buf(&mut self, index: BinaryIndex) -> Result<Vec<u8>> {
276 self.seek(index)?;
277 self.read_bytes()
278 }
279 /// Если `value` содержит еще не прочитанные поля (т.е. содержащие [индексы]), читает их.
280 /// В противном случае просто преобразует тип значения в `SimpleValue`.
281 ///
282 /// Данный метод меняет внутреннюю позицию чтения парсера, однако это не несет за собой
283 /// негативных последствий, если сразу после вызова данного метода выполнить переход к
284 /// следующему токену при итерации по токенам парсера. См. пример в описании структуры
285 /// [`Parser`].
286 ///
287 /// [индексы]: ../index/trait.Index.html
288 /// [`Parser`]: struct.Parser.html
289 pub fn read_value(&mut self, value: SimpleValueRef) -> Result<SimpleValue> {
290 use self::SimpleValueRef::*;
291
292 Ok(match value {
293 Byte(val) => SimpleValue::Byte(val),
294 Char(val) => SimpleValue::Char(val),
295 Word(val) => SimpleValue::Word(val),
296 Short(val) => SimpleValue::Short(val),
297 Dword(val) => SimpleValue::Dword(val),
298 Int(val) => SimpleValue::Int(val),
299 Dword64(val) => SimpleValue::Dword64(self.read_u64(val)?),
300 Int64(val) => SimpleValue::Int64(self.read_i64(val)?),
301 Float(val) => SimpleValue::Float(val),
302 Double(val) => SimpleValue::Double(self.read_f64(val)?),
303 String(val) => SimpleValue::String(self.read_string(val)?),
304 ResRef(val) => SimpleValue::ResRef(self.read_resref(val)?),
305 LocString(val)=> SimpleValue::LocString(self.read_loc_string(val)?),
306 Void(val) => SimpleValue::Void(self.read_byte_buf(val)?),
307 })
308 }
309//-------------------------------------------------------------------------------------------------
310 /// Позиционирует нижележащий считыватель в место, указуемое данным индексом данных GFF.
311 /// Возвращает старую позицию в файле, для того, чтобы можно было затем вернуться в нее.
312 #[inline]
313 fn seek<I: Index>(&mut self, index: I) -> Result<()> {
314 let offset = index.offset(&self.header);
315 self.reader.seek(SeekFrom::Start(offset))?;
316 Ok(())
317 }
318 /// Получает текущую позицию в файле
319 #[inline]
320 fn offset(&mut self) -> Result<SeekFrom> {
321 Ok(SeekFrom::Start(self.reader.seek(SeekFrom::Current(0))?))
322 }
323//-------------------------------------------------------------------------------------------------
324// Чтение вспомогательных данных
325//-------------------------------------------------------------------------------------------------
326 /// Читает 4 байта из текущей позиции и интерпретирует их, как беззнаковое целое
327 #[inline]
328 fn read_u32(&mut self) -> Result<u32> {
329 Ok(self.reader.read_u32::<LE>()?)
330 }
331//-------------------------------------------------------------------------------------------------
332// Чтение значений
333//-------------------------------------------------------------------------------------------------
334 /// Читает 4 байта длины и следующие за ними байты массива, возвращает прочитанный массив
335 #[inline]
336 fn read_bytes(&mut self) -> Result<Vec<u8>> {
337 let size = self.read_u32()? as usize;
338 let mut bytes = Vec::with_capacity(size);
339 unsafe { bytes.set_len(size); }
340
341 self.reader.read_exact(&mut bytes)?;
342 Ok(bytes)
343 }
344 /// Читает 4 байта длины и следующие за ними байты строки, интерпретирует их в соответствии с
345 /// кодировкой декодера и возвращает полученную строку
346 #[inline]
347 fn read_string_impl(&mut self) -> Result<String> {
348 let bytes = self.read_bytes()?;
349
350 Ok(self.encoding.decode(&bytes, self.trap)?)
351 }
352 #[inline]
353 fn read_substring(&mut self) -> Result<SubString> {
354 Ok(SubString {
355 key : StringKey(self.read_u32()?),
356 string: self.read_string_impl()?,
357 })
358 }
359 /// Читает из потока примитивное значение в соответствии с указанным тегом
360 ///
361 /// # Параметры
362 /// - `tag`: Вид данных, которые требуется прочитать. Известные данные расположены в
363 /// диапазоне `[0; 13]`, для остальных значений возвращается ошибка [`Error::UnknownValue`]
364 ///
365 /// # Возвращаемое значение
366 /// Возвращает лениво читаемое значение. Если данные хранятся непосредственно за тегом, то
367 /// они будут уже прочитаны, в противном случае читается только адрес их местонахождения в файле.
368 /// Таким образом, если данные не нужны, лишних чтений не будет
369 ///
370 /// [`Error::UnknownValue`]: ../../error/enum.Error.html#variant.UnknownValue
371 fn read_value_ref(&mut self, tag: u32) -> Result<SimpleValueRef> {
372 use self::SimpleValueRef::*;
373
374 let value = match tag {
375 0 => Byte (self.reader.read_u8()?),
376 1 => Char (self.reader.read_i8()?),
377 2 => Word (self.reader.read_u16::<LE>()?),
378 3 => Short(self.reader.read_i16::<LE>()?),
379 4 => Dword(self.reader.read_u32::<LE>()?),
380 5 => Int (self.reader.read_i32::<LE>()?),
381 8 => Float(self.reader.read_f32::<LE>()?),
382
383 6 => Dword64 (U64Index(self.read_u32()?)),
384 7 => Int64 (I64Index(self.read_u32()?)),
385 9 => Double (F64Index(self.read_u32()?)),
386 10 => String (StringIndex(self.read_u32()?)),
387 11 => ResRef (ResRefIndex(self.read_u32()?)),
388 12 => LocString(LocStringIndex(self.read_u32()?)),
389 13 => Void (BinaryIndex(self.read_u32()?)),
390 tag => return Err(Error::UnknownValue { tag, value: self.read_u32()? }),
391 };
392 Ok(value)
393 }
394}
395
396impl<R: Read + Seek> Iterator for Parser<R> {
397 type Item = Token;
398
399 fn next(&mut self) -> Option<Token> {
400 if let State::Finish = self.state {
401 return None;
402 }
403 let res = self.next_token();
404 if let Err(Error::ParsingFinished) = res {
405 return None;
406 }
407 Some(res.expect("Can't read token"))
408 }
409
410 #[inline]
411 fn size_hint(&self) -> (usize, Option<usize>) {
412 (self.header.token_count(), None)
413 }
414}
415
416impl<R: Read + Seek> FusedIterator for Parser<R> {}