Skip to main content

serde_gff/
raw.rs

1//! Вспомогательный модуль, содержащий описание структур, непосредственно хранимых
2//! в GFF файле на диске. Обычно нет необходимости использовать данный модуль -- он
3//! может понадобиться только при отладке
4use std::fmt;
5use std::io::{Cursor, Read, Seek, SeekFrom, Write, Result};
6use byteorder::{LE, ReadBytesExt, WriteBytesExt};
7
8use crate::header::Header;
9use crate::Label;
10
11/// Типы полей, которые возможно встретить в GFF файле
12#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
13#[repr(u32)]
14pub enum FieldType {
15  /// Беззнаковое байтовое значение (от 0 до 255), занимающее один байт
16  Byte,
17  /// Символ текста в диапазоне `0x00-0xFF`, занимающий один байт
18  Char,
19  /// Беззнаковое целое (от 0 до 65535), занимающее 2 байта
20  Word,
21  /// Знаковое целое (от -32768 до 32767), занимающее 2 байта
22  Short,
23  /// Беззнаковое целое (от 0 до 4294967296), занимающее 4 байта
24  Dword,
25  /// Знаковое целое (от -2147483648 до 2147483647), занимающее 4 байта
26  Int,
27  /// Беззнаковое целое (от 0 до примерно 18e+18), занимающее 8 байт
28  Dword64,
29  /// Знаковое целое (примерно от -9e+18 до +9e+18), занимающее 8 байт
30  Int64,
31  /// Число с плавающей запятой одинарной точности, занимающее 4 байта
32  Float,
33  /// Число с плавающей запятой двойной точности, занимающее 8 байт
34  Double,
35  /// Нелокализуемая строка.
36  ///
37  /// Предпочитаемый максимальный размер - 1024 символа. Это ограничение установлено в первую
38  /// очередь для того, чтобы сохранить пропускную способность сети в том случае, если строку
39  /// необходимо передавать с сервера на клиент.
40  ///
41  /// Данный вид строк не должен использоваться для текста, который может увидеть игрок, так как
42  /// он будет одинаковым независимо от языка клиента игры. Область применения данного типа -
43  /// текст для разработчиков/дизайнеров уровней, например, тегов объектов, используемых в скриптах.
44  String,
45  /// Имя файла ресурса, до 16 символов
46  ResRef,
47  /// Локализуемая строка. Содержит `StringRef` и несколько `CExoString`, каждую со своим номером языка
48  LocString,
49  /// Произвольные данные любой длины
50  Void,
51  /// Вложенная структура
52  Struct,
53  /// Список значений любой длины
54  List,
55}
56impl FieldType {
57  /// Возвращает `true`, если данные поля указанного типа хранятся не в структуре [`Field`], а
58  /// в отдельной области полей GFF файла. Поля типа `Struct` и `List` хранятся совершенно отдельно
59  /// и данный метод для них возвращает `false`
60  ///
61  /// [`Field`]: struct.Field.html
62  #[inline]
63  pub fn is_complex(&self) -> bool {
64    use self::FieldType::*;
65
66    match *self {
67      Dword64 | Int64 | Double | String | ResRef | LocString | Void => true,
68      _ => false
69    }
70  }
71  /// Возвращает `true`, если данные поля указанного типа хранятся внутри структуры [`Field`]
72  ///
73  /// [`Field`]: struct.Field.html
74  #[inline]
75  pub fn is_simple(&self) -> bool {
76    !self.is_complex() && *self != FieldType::Struct && *self != FieldType::List
77  }
78  //TODO: После стабилизации https://github.com/rust-lang/rust/issues/33417 полностью перенести в TryFrom
79  #[inline]
80  fn from_u32(value: u32) -> Option<Self> {
81    use self::FieldType::*;
82
83    Some(match value {
84       0 => Byte,
85       1 => Char,
86       2 => Word,
87       3 => Short,
88       4 => Dword,
89       5 => Int,
90       6 => Dword64,
91       7 => Int64,
92       8 => Float,
93       9 => Double,
94      10 => String,
95      11 => ResRef,
96      12 => LocString,
97      13 => Void,
98      14 => Struct,
99      15 => List,
100      _ => return None,
101    })
102  }
103}
104
105#[cfg(nightly)]
106impl TryFrom<u32> for FieldType {
107  type Error = NoneError;
108
109  #[inline]
110  fn try_from(value: u32) -> Result<Self, Self::Error> {
111    Ok(self.from_u32(value)?)
112  }
113}
114
115/// Описание структуры, как оно хранится в GFF файле
116pub struct Struct {
117  /// Идентификатор типа структуры. Игрой на самом деле почти никогда не используется.
118  /// При записи сюда сериализатор всегда записывает сюда 0
119  pub tag: u32,
120  /// Или индекс в массив полей (если `self.fields == 1`), или в смещение в массиве индексов полей
121  pub offset: u32,
122  /// Количество полей структуры
123  pub fields: u32,
124}
125impl Struct {
126  /// Читает 12 байт значения структуры из потока
127  #[inline]
128  pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
129    Ok(Struct {
130      tag:    reader.read_u32::<LE>()?,
131      offset: reader.read_u32::<LE>()?,
132      fields: reader.read_u32::<LE>()?,
133    })
134  }
135  /// Записывает 12 байт значения структуры в поток
136  #[inline]
137  pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
138    writer.write_u32::<LE>(self.tag)?;
139    writer.write_u32::<LE>(self.offset)?;
140    writer.write_u32::<LE>(self.fields)?;
141    Ok(())
142  }
143}
144impl fmt::Debug for Struct {
145  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146    write!(f, "Struct {{ tag: {:?}, offset: {:?}, fields: {:?} }}", self.tag, self.offset, self.fields)
147  }
148}
149
150/// Описание поля структуры, как оно хранится в GFF файле
151pub struct Field {
152  /// Идентификатор типа поля
153  pub tag: u32,
154  /// Индекс в массив меток, определяющий метку, привязанную к данному полю
155  pub label: u32,
156  /// Сами данные для простых данных или смещение в массиве с данными для комплексных
157  /// типов. Также, если поле представляет собой структуру, то это индекс в массиве
158  /// структур, а если список -- байтовое смещение в массиве списков (хотя сам массив списков
159  /// состоит из элементов размером 4 байта).
160  pub data: [u8; 4],
161}
162impl Field {
163  /// Читает 12 байт значения поля из потока
164  #[inline]
165  pub fn read<R: Read>(reader: &mut R) -> Result<Self> {
166    let tag   = reader.read_u32::<LE>()?;
167    let label = reader.read_u32::<LE>()?;
168    let mut data = [0u8; 4];
169    reader.read_exact(&mut data)?;
170
171    Ok(Field { tag, label, data })
172  }
173  /// Записывает 12 байт значения поля в поток
174  #[inline]
175  pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
176    writer.write_u32::<LE>(self.tag as u32)?;
177    writer.write_u32::<LE>(self.label)?;
178    writer.write_all(&self.data)?;
179    Ok(())
180  }
181}
182impl fmt::Debug for Field {
183  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
184    write!(f, "Field {{ tag: {:?}, label: {:?}, data: {:?} }}", self.tag, self.label, self.data)
185  }
186}
187
188/// Данные для одного поля, хранимые в поле [`Gff::field_data`]. Используется для улучшения отладочного вывода
189///
190/// [`Gff::field_data`]: ../struct.Gff.html#field.field_data
191struct FieldData<'a>(&'a [u8]);
192impl<'a> fmt::Debug for FieldData<'a> {
193  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
194    write!(f, "{:?}", self.0)
195  }
196}
197/// Представление данных комплексных полей для отладочного вывода
198#[derive(Debug)]
199struct DebugFieldData<'a> {
200  /// Данные, разбитые по принадлежности к отдельным полям, для удобства отладочного вывода
201  by_field: Vec<FieldData<'a>>,
202  /// Данные в том виде, в каком они хранятся в файле
203  raw: &'a [u8],
204}
205
206/// Список индексов для одной структуры, хранимые в поле [`Gff::field_indices`]
207///
208/// [`Gff::field_indices`]: ../struct.Gff.html#field.field_indices
209struct FieldIndex<'a>(&'a [u32]);
210impl<'a> fmt::Debug for FieldIndex<'a> {
211  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212    write!(f, "{:?}", self.0)
213  }
214}
215/// Представление списка индексов полей структур для отладочного вывода
216#[derive(Debug)]
217struct DebugFieldIndex<'a> {
218  /// Данные, разбитые по принадлежности к отдельным структурам, для удобства отладочного вывода
219  by_struct: Vec<FieldIndex<'a>>,
220  /// Данные в том виде, в каком они хранятся в файле
221  raw: &'a [u32],
222}
223
224/// Список индексов для одного списка, хранимый в поле [`Gff::list_indices`]
225///
226/// [`Gff::list_indices`]: ../struct.Gff.html#field.list_indices
227struct ListIndex<'a>(&'a [u32]);
228impl<'a> fmt::Debug for ListIndex<'a> {
229  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
230    write!(f, "{:?}", self.0)
231  }
232}
233/// Представление списка индексов полей структур для отладочного вывода
234#[derive(Debug)]
235struct DebugListIndex<'a> {
236  /// Данные, разбитые по принадлежности к отдельным спискам и без длины, для удобства отладочного вывода
237  by_list: Vec<ListIndex<'a>>,
238  /// Данные в том виде, в каком они хранятся в файле
239  raw: &'a [u32],
240}
241
242/// Описание всей структуры GFF файла, как она хранится в GFF файле
243pub struct Gff {
244  /// Заголовок файла, содержащий метаинформацию о нем: тип содержимого, версию структуры,
245  /// количество и местоположение структур в файле
246  pub header:        Header,
247  /// Список структур внутри GFF файла. Структура -- группирующий элемент, состоящий
248  /// из [полей], помеченных [метками]
249  ///
250  /// [полей]: struct.Field.html
251  /// [метками]: ../struct.Label.html
252  pub structs:       Vec<Struct>,
253  /// Список полей из всех структур GFF файла. Каждое поле ссылается на [метку] и данные,
254  /// а также имеет некоторый тип
255  ///
256  /// [метку]: ../struct.Label.html
257  pub fields:        Vec<Field>,
258  /// Список меток из всех полей GFF файла. В корректном GFF файле каждая метка должна быть
259  /// уникальна, однако неуникальность не является фатальной ошибкой -- просто неэффективным
260  /// расходованием места
261  pub labels:        Vec<Label>,
262  /// Данные для значений полей, которые не влезают в 4 байта и не могут храниться в структуре
263  /// [поля](struct.Field.html)
264  pub field_data:    Vec<u8>,
265  /// Плоский массив, содержащий индексы полей, которые входят в каждую структуру, содержащую
266  /// более одного поля. Например, при наличии двух структур, первая из которых ссылается на поля
267  /// 0 и 1, а вторая на поля 2, 3 и 4, массив может содержать `[0, 1, 2, 3, 4]` или `[2, 3, 4, 0, 1]`,
268  /// в зависимости от того, в каком порядке будут записаны структуры
269  pub field_indices: Vec<u32>,
270  /// Плоский массив индексов структуры, которые входят в списки. Каждый элемент массива описывает
271  /// или индекс структуры, или количество следующих индексов в массиве, которые относятся к одному
272  /// списку. Например, если файл содержит два поля-списка, первое из которых состоит из структур
273  /// 1 и 3, а второй -- из структур 0, 2 и 4, то массив может содержать `[2, 1, 3, 3, 0, 2, 4]`
274  /// или `[3, 0, 2, 4, 2, 1, 3]` в зависимости от порядка записи списков. Каждый подсписок начинается
275  /// с числа, указывающего его размер: в данном примере `[2| 1, 3]` и `[3| 0, 2, 4]`
276  pub list_indices:  Vec<u32>,
277}
278
279macro_rules! read_exact {
280  ($reader:expr, $section:expr, $type:ident) => ({
281    $reader.seek(SeekFrom::Start($section.offset as u64))?;
282    let mut vec = Vec::with_capacity($section.count as usize);
283    for _ in 0..$section.count {
284      vec.push($type::read($reader)?);
285    }
286    vec
287  });
288}
289
290macro_rules! read_into {
291  ($reader:expr, $section:expr) => ({
292    $reader.seek(SeekFrom::Start($section.offset as u64))?;
293    let mut vec = Vec::with_capacity($section.count as usize);
294    unsafe { vec.set_len(($section.count / 4) as usize); }
295    $reader.read_u32_into::<LE>(&mut vec[..])?;
296    vec
297  });
298}
299
300macro_rules! write_all {
301  ($writer:expr, $list:expr) => (
302    for elem in &$list {
303      elem.write($writer)?;
304    }
305  );
306  ($writer:expr, $list:expr, LE) => (
307    for elem in &$list {
308      $writer.write_u32::<LE>(*elem)?;
309    }
310  );
311}
312
313impl Gff {
314  /// Осуществляет чтение GFF формата из указанного источника данных
315  pub fn read<R: Read + Seek>(reader: &mut R) -> Result<Gff> {
316    let header  = Header::read(reader)?;
317    let structs = read_exact!(reader, header.structs, Struct);
318    let fields  = read_exact!(reader, header.fields , Field);
319
320    reader.seek(SeekFrom::Start(header.labels.offset as u64))?;
321    let mut labels = Vec::with_capacity(header.labels.count as usize);
322    for _ in 0..header.labels.count {
323      let mut label = [0u8; 16];
324      reader.read_exact(&mut label)?;
325      labels.push(label.into());
326    }
327
328    reader.seek(SeekFrom::Start(header.field_data.offset as u64))?;
329    let mut field_data = Vec::with_capacity(header.field_data.count as usize);
330    unsafe { field_data.set_len(header.field_data.count as usize); }
331    reader.read_exact(&mut field_data[..])?;
332
333    let field_indices = read_into!(reader, header.field_indices);
334    let list_indices  = read_into!(reader, header.list_indices);
335
336    Ok(Gff { header, structs, fields, labels, field_data, field_indices, list_indices })
337  }
338  /// Записывает всю GFF структуру в указанный поток
339  pub fn write<W: Write>(&self, writer: &mut W) -> Result<()> {
340    self.header.write(writer)?;
341    write_all!(writer, self.structs);
342    write_all!(writer, self.fields);
343    for label in &self.labels {
344      writer.write_all(label.as_ref())?;
345    }
346    writer.write_all(&self.field_data)?;
347    write_all!(writer, self.field_indices, LE);
348    write_all!(writer, self.list_indices, LE);
349    Ok(())
350  }
351
352  /// Разделяет плоский список с данными полей на массив, содержащий по порции данных на
353  /// каждое поле. Вспомогательный массив `offsets` содержит смещения внутри массива с данными
354  /// для каждого поля
355  fn split_data<'a>(data: &'a [u8], offsets: &[u32]) -> DebugFieldData<'a> {
356    let it1 = offsets.iter();
357    let it2 = offsets.iter().skip(1);
358
359    let mut vec = Vec::with_capacity(offsets.len() - 1);
360    for (s, e) in it1.zip(it2) {
361      vec.push(FieldData(&data[*s as usize .. *e as usize]));
362    }
363    DebugFieldData { by_field: vec, raw: data }
364  }
365  /// Разделяет плоский список с индексами полей структур на массив, содержащий по списку
366  /// полей на каждую структуру. Вспомогательный массив `offsets` содержит для каждой структуры
367  /// номер первого элемента и количество элементов
368  fn split_fields<'a>(data: &'a [u32], offsets: &[(u32, u32)]) -> DebugFieldIndex<'a> {
369    let mut vec = Vec::with_capacity(offsets.len() - 1);
370    for (s, cnt) in offsets {
371      vec.push(FieldIndex(&data[*s as usize .. (*s + cnt) as usize]));
372    }
373    DebugFieldIndex { by_struct: vec, raw: data }
374  }
375  /// Разделяет плоский список с индексами элементов списка на массив, содержащий по списку
376  /// структур на каждый GFF список
377  fn split_lists<'a>(data: &'a [u32]) -> DebugListIndex<'a> {
378    let mut vec = Vec::new();
379    let mut it = data.iter().enumerate();
380    while let Some((i, cnt)) = it.next() {
381      let from = i + 1;
382      let to = from + *cnt as usize;
383      vec.push(ListIndex(&data[from..to]));
384      while let Some((j, _)) = it.next() {
385        if j >= to { break; }
386      }
387    }
388    DebugListIndex { by_list: vec, raw: data }
389  }
390}
391
392impl fmt::Debug for Gff {
393  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
394    let data_offsets: Vec<_> = self.fields.iter()
395      // Оставляем только те поля, для которых данных хранятся в массиве field_data
396      .filter(|f| FieldType::from_u32(f.tag).as_ref().map(FieldType::is_complex).unwrap_or(false))
397      .map(|f| Cursor::new(f.data).read_u32::<LE>().unwrap())
398      .collect();
399    let field_offsets: Vec<_> = self.structs.iter()
400      // Списки полей используются только для структур, которые имеют более 2-х полей
401      .filter(|s| s.fields > 1)
402      // Смещение указано в байтах, а нам требуется в элементах, поэтому делим на размер элемента
403      .map(|s| (s.offset / 4, s.fields))
404      .collect();
405
406    f.debug_struct("Gff")
407      .field("header",        &self.header)
408      .field("structs",       &self.structs)
409      .field("fields",        &self.fields)
410      .field("labels",        &self.labels)
411      .field("field_data",    &Self::split_data(&self.field_data, &data_offsets))
412      .field("field_indices", &Self::split_fields(&self.field_indices, &field_offsets))
413      .field("list_indices",  &Self::split_lists(&self.list_indices))
414      .finish()
415  }
416}