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> {}