-use crate::endian::{Endian, Parse, ToBytes};
+use crate::{
+ endian::{Endian, Parse, ToBytes},
+ identifier::{Error as IdError, Identifier},
+};
use encoding_rs::{mem::decode_latin1, DecoderResult, Encoding};
use flate2::read::ZlibDecoder;
#[error("Invalid variable display alignment value {0}")]
InvalidAlignment(u32),
+ #[error("Invalid attribute name. {0}")]
+ InvalidAttributeName(IdError),
+
+ #[error("Invalid variable name in attribute record. {0}")]
+ InvalidAttributeVariableName(IdError),
+
+ #[error("Invalid short name in long variable name record. {0}")]
+ InvalidShortName(IdError),
+
+ #[error("Invalid name in long variable name record. {0}")]
+ InvalidLongName(IdError),
+
+ #[error("Invalid variable name in very long string record. {0}")]
+ InvalidLongStringName(IdError),
+
+ #[error("Invalid variable name in variable set record. {0}")]
+ InvalidVariableSetName(IdError),
+
#[error("Details TBD")]
TBD,
}
output.into()
}
}
+
+ pub fn decode_identifier(&self, input: &RawString) -> Result<Identifier, IdError> {
+ self.new_identifier(&self.decode(input))
+ }
+
+ pub fn new_identifier(&self, name: &str) -> Result<Identifier, IdError> {
+ Identifier::new(name, self.encoding)
+ }
}
impl<S> Header for HeaderRecord<S>
TextRecordType::FileAttributes => {
Ok(FileAttributeRecord::decode(self, decoder).map(|fa| Record::FileAttributes(fa)))
}
- TextRecordType::VariableAttributes => {
- Ok(Some(Record::VariableAttributes(
-VariableAttributeRecord::decode(self, decoder))))
- }
+ TextRecordType::VariableAttributes => Ok(Some(Record::VariableAttributes(
+ VariableAttributeRecord::decode(self, decoder),
+ ))),
}
}
}
#[derive(Clone, Debug)]
pub struct VeryLongString {
- pub short_name: String,
+ pub short_name: Identifier,
pub length: u16,
}
let Some((short_name, length)) = input.split_once('=') else {
return Err(Error::TBD);
};
+ let short_name = decoder
+ .new_identifier(short_name)
+ .map_err(Error::InvalidLongStringName)?;
let length = length.parse().map_err(|_| Error::TBD)?;
- Ok(VeryLongString {
- short_name: short_name.into(),
- length,
- })
+ Ok(VeryLongString { short_name, length })
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct VeryLongStringsRecord(Vec<VeryLongString>);
+
+impl VeryLongStringsRecord {
+ fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
+ let input = decoder.decode(&source.text);
+ let mut very_long_strings = Vec::new();
+ for tuple in input
+ .split('\0')
+ .map(|s| s.trim_end_matches('\t'))
+ .filter(|s| !s.is_empty())
+ {
+ if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&decoder.warn) {
+ very_long_strings.push(vls)
+ }
+ }
+ VeryLongStringsRecord(very_long_strings)
}
}
#[derive(Clone, Debug)]
pub struct Attribute {
- pub name: String,
+ pub name: Identifier,
pub values: Vec<String>,
}
let Some((name, mut input)) = input.split_once('(') else {
return Err(Error::TBD);
};
+ let name = decoder
+ .new_identifier(name)
+ .map_err(Error::InvalidAttributeName)?;
let mut values = Vec::new();
loop {
let Some((value, rest)) = input.split_once('\n') else {
values.push(value.into());
}
if let Some(rest) = rest.strip_prefix(')') {
- let attribute = Attribute {
- name: name.into(),
- values,
- };
+ let attribute = Attribute { name, values };
return Ok((attribute, rest));
};
input = rest;
#[derive(Clone, Debug)]
pub struct VarAttributeSet {
- pub long_var_name: String,
+ pub long_var_name: Identifier,
pub attributes: AttributeSet,
}
let Some((long_var_name, rest)) = input.split_once(':') else {
return Err(Error::TBD);
};
+ let long_var_name = decoder
+ .new_identifier(long_var_name)
+ .map_err(Error::InvalidAttributeVariableName)?;
let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'))?;
let var_attribute = VarAttributeSet {
- long_var_name: long_var_name.into(),
+ long_var_name,
attributes,
};
Ok((var_attribute, rest))
}
#[derive(Clone, Debug)]
-pub struct VeryLongStringsRecord(Vec<VeryLongString>);
-
-impl VeryLongStringsRecord {
- fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
- let input = decoder.decode(&source.text);
- let mut very_long_strings = Vec::new();
- for tuple in input
- .split('\0')
- .map(|s| s.trim_end_matches('\t'))
- .filter(|s| !s.is_empty())
- {
- if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&decoder.warn) {
- very_long_strings.push(vls)
- }
- }
- VeryLongStringsRecord(very_long_strings)
- }
+pub struct LongName {
+ pub short_name: Identifier,
+ pub long_name: Identifier,
}
-#[derive(Clone, Debug)]
-pub struct LongName {
- pub short_name: String,
- pub long_name: String,
+impl LongName {
+ fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
+ let Some((short_name, long_name)) = input.split_once('=') else {
+ return Err(Error::TBD);
+ };
+ let short_name = decoder
+ .new_identifier(short_name)
+ .map_err(Error::InvalidShortName)?;
+ let long_name = decoder
+ .new_identifier(long_name)
+ .map_err(Error::InvalidLongName)?;
+ Ok(LongName {
+ short_name,
+ long_name,
+ })
+ }
}
#[derive(Clone, Debug)]
let input = decoder.decode(&source.text);
let mut names = Vec::new();
for pair in input.split('\t').filter(|s| !s.is_empty()) {
- if let Some((short_name, long_name)) = pair.split_once('=') {
- names.push(LongName {
- short_name: short_name.into(),
- long_name: long_name.into(),
- });
- } else {
- decoder.warn(Error::TBD)
+ if let Some(long_name) = LongName::parse(pair, decoder).warn_on_error(&decoder.warn) {
+ names.push(long_name);
}
}
LongNamesRecord(names)
#[derive(Clone, Debug)]
pub struct VariableSet {
pub name: String,
- pub vars: Vec<String>,
+ pub vars: Vec<Identifier>,
}
impl VariableSet {
- fn parse(input: &str) -> Result<Self, Error> {
+ fn parse(input: &str, decoder: &Decoder) -> Result<Self, Error> {
let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
- let vars = input.split_ascii_whitespace().map(String::from).collect();
+ let mut vars = Vec::new();
+ for var in input.split_ascii_whitespace() {
+ if let Some(identifier) = decoder
+ .new_identifier(var)
+ .map_err(Error::InvalidVariableSetName)
+ .warn_on_error(&decoder.warn)
+ {
+ vars.push(identifier);
+ }
+ }
Ok(VariableSet {
name: name.into(),
vars,
let mut sets = Vec::new();
let input = decoder.decode(&source.text);
for line in input.lines() {
- if let Some(set) = VariableSet::parse(line).warn_on_error(&decoder.warn) {
+ if let Some(set) = VariableSet::parse(line, decoder).warn_on_error(&decoder.warn) {
sets.push(set)
}
}