2e67965e41ff730f7fed916b22cc9d3f31cedc1a
[pspp] / rust / src / cooked.rs
1 use std::{borrow::Cow, cmp::Ordering, collections::HashMap, iter::repeat};
2
3 use crate::{
4     encoding::{default_encoding, get_encoding, Error as EncodingError},
5     endian::Endian,
6     format::{Error as FormatError, Spec, UncheckedSpec},
7     identifier::{Error as IdError, Identifier},
8     raw::{self, MissingValues, UnencodedStr, VarType},
9 };
10 use chrono::{NaiveDate, NaiveDateTime, NaiveTime};
11 use encoding_rs::{DecoderResult, Encoding};
12 use num::integer::div_ceil;
13 use ordered_float::OrderedFloat;
14 use thiserror::Error as ThisError;
15
16 pub use crate::raw::{CategoryLabels, Compression};
17
18 #[derive(ThisError, Debug)]
19 pub enum Error {
20     // XXX this is really an internal error and maybe we should change the
21     // interfaces to make it impossible
22     #[error("Missing header record")]
23     MissingHeaderRecord,
24
25     #[error("{0}")]
26     EncodingError(EncodingError),
27
28     #[error("Using default encoding {0}.")]
29     UsingDefaultEncoding(String),
30
31     #[error("Variable record at offset {offset:#x} specifies width {width} not in valid range [-1,255).")]
32     InvalidVariableWidth { offset: u64, width: i32 },
33
34     #[error("This file has corrupted metadata written by a buggy version of PSPP.  To ensure that other software can read it correctly, save a new copy of the file.")]
35     InvalidLongMissingValueFormat,
36
37     #[error("File creation date {creation_date} is not in the expected format \"DD MMM YY\" format.  Using 01 Jan 1970.")]
38     InvalidCreationDate { creation_date: String },
39
40     #[error("File creation time {creation_time} is not in the expected format \"HH:MM:SS\" format.  Using midnight.")]
41     InvalidCreationTime { creation_time: String },
42
43     #[error("{id_error}  Renaming variable to {new_name}.")]
44     InvalidVariableName {
45         id_error: IdError,
46         new_name: Identifier,
47     },
48
49     #[error(
50         "Substituting {new_spec} for invalid print format on variable {variable}.  {format_error}"
51     )]
52     InvalidPrintFormat {
53         new_spec: Spec,
54         variable: Identifier,
55         format_error: FormatError,
56     },
57
58     #[error(
59         "Substituting {new_spec} for invalid write format on variable {variable}.  {format_error}"
60     )]
61     InvalidWriteFormat {
62         new_spec: Spec,
63         variable: Identifier,
64         format_error: FormatError,
65     },
66
67     #[error("Renaming variable with duplicate name {duplicate_name} to {new_name}.")]
68     DuplicateVariableName {
69         duplicate_name: Identifier,
70         new_name: Identifier,
71     },
72
73     #[error("Dictionary index {dict_index} is outside valid range [1,{max_index}].")]
74     InvalidDictIndex { dict_index: usize, max_index: usize },
75
76     #[error("Dictionary index {0} refers to a long string continuation.")]
77     DictIndexIsContinuation(usize),
78
79     #[error("Variables associated with value label are not all of identical type.  Variable {numeric_var} is numeric, but variable {string_var} is string.")]
80     ValueLabelsDifferentTypes {
81         numeric_var: Identifier,
82         string_var: Identifier,
83     },
84
85     #[error(
86         "Value labels may not be added to long string variable {0} using record types 3 or 4."
87     )]
88     InvalidLongStringValueLabel(Identifier),
89
90     #[error("Invalid multiple response set name.  {0}")]
91     InvalidMrSetName(IdError),
92
93     #[error("Multiple response set {mr_set} includes unknown variable {short_name}.")]
94     UnknownMrSetVariable {
95         mr_set: Identifier,
96         short_name: Identifier,
97     },
98
99     #[error("Multiple response set {0} has no variables.")]
100     EmptyMrSet(Identifier),
101
102     #[error("Multiple response set {0} has only one variable.")]
103     OneVarMrSet(Identifier),
104
105     #[error("Multiple response set {0} contains both string and numeric variables.")]
106     MixedMrSet(Identifier),
107
108     #[error(
109         "Invalid numeric format for counted value {number} in multiple response set {mr_set}."
110     )]
111     InvalidMDGroupCountedValue { mr_set: Identifier, number: String },
112
113     #[error("Counted value {value} has width {width}, but it must be no wider than {max_width}, the width of the narrowest variable in multiple response set {mr_set}.")]
114     TooWideMDGroupCountedValue {
115         mr_set: Identifier,
116         value: String,
117         width: usize,
118         max_width: u16,
119     },
120
121     #[error("Long string value label for variable {name} has width {width}, which is not in the valid range [{min_width},{max_width}].")]
122     InvalidLongValueLabelWidth {
123         name: Identifier,
124         width: u32,
125         min_width: u16,
126         max_width: u16,
127     },
128
129     #[error("Invalid attribute name.  {0}")]
130     InvalidAttributeName(IdError),
131
132     #[error("Invalid short name in long variable name record.  {0}")]
133     InvalidShortName(IdError),
134
135     #[error("Invalid name in long variable name record.  {0}")]
136     InvalidLongName(IdError),
137
138     #[error("Invalid variable name in very long string record.  {0}")]
139     InvalidLongStringName(IdError),
140
141     #[error("Invalid variable name in long string value label record.  {0}")]
142     InvalidLongStringValueLabelName(IdError),
143
144     #[error("Invalid variable name in attribute record.  {0}")]
145     InvalidAttributeVariableName(IdError),
146
147     // XXX This is risky because `text` might be arbitarily long.
148     #[error("Text string contains invalid bytes for {encoding} encoding: {text}")]
149     MalformedString { encoding: String, text: String },
150
151     #[error("Invalid variable measurement level value {0}")]
152     InvalidMeasurement(u32),
153
154     #[error("Invalid variable display alignment value {0}")]
155     InvalidAlignment(u32),
156
157     #[error("Details TBD")]
158     TBD,
159 }
160
161 #[derive(Clone, Debug)]
162 pub enum Record {
163     Header(HeaderRecord),
164     Variable(VariableRecord),
165     ValueLabel(ValueLabelRecord),
166     Document(DocumentRecord),
167     IntegerInfo(IntegerInfoRecord),
168     FloatInfo(FloatInfoRecord),
169     VariableSets(VariableSetRecord),
170     VarDisplay(VarDisplayRecord),
171     MultipleResponse(MultipleResponseRecord),
172     LongStringValueLabels(LongStringValueLabelRecord),
173     Encoding(EncodingRecord),
174     NumberOfCases(NumberOfCasesRecord),
175     ProductInfo(ProductInfoRecord),
176     LongNames(LongNameRecord),
177     VeryLongStrings(VeryLongStringRecord),
178     FileAttributes(FileAttributeRecord),
179     VariableAttributes(VariableAttributeRecord),
180     OtherExtension(Extension),
181     //EndOfHeaders(u32),
182     //ZHeader(ZHeader),
183     //ZTrailer(ZTrailer),
184     //Case(Vec<Value>),
185 }
186
187 pub use crate::raw::EncodingRecord;
188 pub use crate::raw::Extension;
189 pub use crate::raw::FloatInfoRecord;
190 pub use crate::raw::IntegerInfoRecord;
191 pub use crate::raw::NumberOfCasesRecord;
192
193 type DictIndex = usize;
194
195 pub struct Variable {
196     pub dict_index: DictIndex,
197     pub short_name: Identifier,
198     pub long_name: Option<Identifier>,
199     pub width: VarWidth,
200 }
201
202 pub struct Decoder {
203     pub compression: Option<Compression>,
204     pub endian: Endian,
205     pub encoding: &'static Encoding,
206     pub variables: HashMap<DictIndex, Variable>,
207     pub var_names: HashMap<Identifier, DictIndex>,
208     n_dict_indexes: usize,
209     n_generated_names: usize,
210 }
211
212 pub fn decode(
213     headers: Vec<raw::Record>,
214     encoding: Option<&'static Encoding>,
215     warn: &impl Fn(Error),
216 ) -> Result<Vec<Record>, Error> {
217     let Some(header_record) = headers.iter().find_map(|rec| {
218         if let raw::Record::Header(header) = rec {
219             Some(header)
220         } else {
221             None
222         }
223     }) else {
224         return Err(Error::MissingHeaderRecord);
225     };
226     let encoding = match encoding {
227         Some(encoding) => encoding,
228         None => {
229             let encoding = headers.iter().find_map(|rec| {
230                 if let raw::Record::Encoding(ref e) = rec {
231                     Some(e.0.as_str())
232                 } else {
233                     None
234                 }
235             });
236             let character_code = headers.iter().find_map(|rec| {
237                 if let raw::Record::IntegerInfo(ref r) = rec {
238                     Some(r.character_code)
239                 } else {
240                     None
241                 }
242             });
243             match get_encoding(encoding, character_code) {
244                 Ok(encoding) => encoding,
245                 Err(err @ EncodingError::Ebcdic) => return Err(Error::EncodingError(err)),
246                 Err(err) => {
247                     warn(Error::EncodingError(err));
248                     // Warn that we're using the default encoding.
249                     default_encoding()
250                 }
251             }
252         }
253     };
254
255     let mut decoder = Decoder {
256         compression: header_record.compression,
257         endian: header_record.endian,
258         encoding,
259         variables: HashMap::new(),
260         var_names: HashMap::new(),
261         n_dict_indexes: 0,
262         n_generated_names: 0,
263     };
264
265     let mut output = Vec::with_capacity(headers.len());
266     for header in &headers {
267         match header {
268             raw::Record::Header(ref input) => {
269                 if let Some(header) = HeaderRecord::try_decode(&mut decoder, input, warn)? {
270                     output.push(Record::Header(header))
271                 }
272             }
273             raw::Record::Variable(ref input) => {
274                 if let Some(variable) = VariableRecord::try_decode(&mut decoder, input, warn)? {
275                     output.push(Record::Variable(variable));
276                 }
277             }
278             raw::Record::ValueLabel(ref input) => {
279                 if let Some(value_label) = ValueLabelRecord::try_decode(&mut decoder, input, warn)?
280                 {
281                     output.push(Record::ValueLabel(value_label));
282                 }
283             }
284             raw::Record::Document(ref input) => {
285                 if let Some(document) = DocumentRecord::try_decode(&mut decoder, input, warn)? {
286                     output.push(Record::Document(document))
287                 }
288             }
289             raw::Record::IntegerInfo(ref input) => output.push(Record::IntegerInfo(input.clone())),
290             raw::Record::FloatInfo(ref input) => output.push(Record::FloatInfo(input.clone())),
291             raw::Record::VariableSets(ref input) => {
292                 let s = decoder.decode_string_cow(&input.text.0, warn);
293                 output.push(Record::VariableSets(VariableSetRecord::parse(&s, warn)?));
294             }
295             raw::Record::VarDisplay(ref input) => {
296                 if let Some(vdr) = VarDisplayRecord::try_decode(&mut decoder, input, warn)? {
297                     output.push(Record::VarDisplay(vdr))
298                 }
299             }
300             raw::Record::MultipleResponse(ref input) => {
301                 if let Some(mrr) = MultipleResponseRecord::try_decode(&mut decoder, input, warn)? {
302                     output.push(Record::MultipleResponse(mrr))
303                 }
304             }
305             raw::Record::LongStringValueLabels(ref input) => {
306                 if let Some(mrr) =
307                     LongStringValueLabelRecord::try_decode(&mut decoder, input, warn)?
308                 {
309                     output.push(Record::LongStringValueLabels(mrr))
310                 }
311             }
312             raw::Record::Encoding(ref input) => output.push(Record::Encoding(input.clone())),
313             raw::Record::NumberOfCases(ref input) => {
314                 output.push(Record::NumberOfCases(input.clone()))
315             }
316             raw::Record::ProductInfo(ref input) => {
317                 let s = decoder.decode_string_cow(&input.text.0, warn);
318                 output.push(Record::ProductInfo(ProductInfoRecord::parse(&s, warn)?));
319             }
320             raw::Record::LongNames(ref input) => {
321                 let s = decoder.decode_string_cow(&input.text.0, warn);
322                 output.push(Record::LongNames(LongNameRecord::parse(
323                     &mut decoder,
324                     &s,
325                     warn,
326                 )?));
327             }
328             raw::Record::VeryLongStrings(ref input) => {
329                 let s = decoder.decode_string_cow(&input.text.0, warn);
330                 output.push(Record::VeryLongStrings(VeryLongStringRecord::parse(
331                     &mut decoder,
332                     &s,
333                     warn,
334                 )?));
335             }
336             raw::Record::FileAttributes(ref input) => {
337                 let s = decoder.decode_string_cow(&input.text.0, warn);
338                 output.push(Record::FileAttributes(FileAttributeRecord::parse(
339                     &decoder, &s, warn,
340                 )?));
341             }
342             raw::Record::VariableAttributes(ref input) => {
343                 let s = decoder.decode_string_cow(&input.text.0, warn);
344                 output.push(Record::VariableAttributes(VariableAttributeRecord::parse(
345                     &decoder, &s, warn,
346                 )?));
347             }
348             raw::Record::OtherExtension(ref input) => {
349                 output.push(Record::OtherExtension(input.clone()))
350             }
351             raw::Record::EndOfHeaders(_) => (),
352             raw::Record::ZHeader(_) => (),
353             raw::Record::ZTrailer(_) => (),
354             raw::Record::Case(_) => (),
355         };
356     }
357     Ok(output)
358 }
359
360 impl Decoder {
361     fn generate_name(&mut self) -> Identifier {
362         loop {
363             self.n_generated_names += 1;
364             let name = Identifier::new(&format!("VAR{:03}", self.n_generated_names), self.encoding)
365                 .unwrap();
366             if !self.var_names.contains_key(&name) {
367                 return name;
368             }
369             assert!(self.n_generated_names < usize::MAX);
370         }
371     }
372     fn decode_string_cow<'a>(&self, input: &'a [u8], warn: &impl Fn(Error)) -> Cow<'a, str> {
373         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
374         if malformed {
375             warn(Error::MalformedString {
376                 encoding: self.encoding.name().into(),
377                 text: output.clone().into(),
378             });
379         }
380         output
381     }
382     fn decode_string(&self, input: &[u8], warn: &impl Fn(Error)) -> String {
383         self.decode_string_cow(input, warn).into()
384     }
385     pub fn decode_identifier(
386         &self,
387         input: &[u8],
388         warn: &impl Fn(Error),
389     ) -> Result<Identifier, IdError> {
390         let s = self.decode_string_cow(input, warn);
391         Identifier::new(&s, self.encoding)
392     }
393     fn get_var_by_index(&self, dict_index: usize) -> Result<&Variable, Error> {
394         let max_index = self.n_dict_indexes;
395         if dict_index == 0 || dict_index > max_index {
396             return Err(Error::InvalidDictIndex {
397                 dict_index,
398                 max_index,
399             });
400         }
401         let Some(variable) = self.variables.get(&(dict_index - 1)) else {
402             return Err(Error::DictIndexIsContinuation(dict_index));
403         };
404         Ok(variable)
405     }
406
407     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
408     /// re-encoding the result back into `self.encoding` will have exactly the
409     /// same length in bytes.
410     ///
411     /// XXX warn about errors?
412     fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
413         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
414             // This is the common case.  Usually there will be no errors.
415             s.into()
416         } else {
417             // Unusual case.  Don't bother to optimize it much.
418             let mut decoder = self.encoding.new_decoder_without_bom_handling();
419             let mut output = String::with_capacity(
420                 decoder
421                     .max_utf8_buffer_length_without_replacement(input.len())
422                     .unwrap(),
423             );
424             let mut rest = input;
425             while !rest.is_empty() {
426                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
427                     (DecoderResult::InputEmpty, _) => break,
428                     (DecoderResult::OutputFull, _) => unreachable!(),
429                     (DecoderResult::Malformed(a, b), consumed) => {
430                         let skipped = a as usize + b as usize;
431                         output.extend(repeat('?').take(skipped));
432                         rest = &rest[consumed..];
433                     }
434                 }
435             }
436             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
437             output.into()
438         }
439     }
440 }
441
442 pub trait TryDecode: Sized {
443     type Input;
444     fn try_decode(
445         decoder: &mut Decoder,
446         input: &Self::Input,
447         warn: impl Fn(Error),
448     ) -> Result<Option<Self>, Error>;
449 }
450
451 pub trait Decode<Input>: Sized {
452     fn decode(decoder: &Decoder, input: &Input, warn: impl Fn(Error)) -> Self;
453 }
454
455 impl<const N: usize> Decode<UnencodedStr<N>> for String {
456     fn decode(decoder: &Decoder, input: &UnencodedStr<N>, warn: impl Fn(Error)) -> Self {
457         decoder.decode_string(&input.0, &warn)
458     }
459 }
460
461 #[derive(Clone, Debug)]
462 pub struct HeaderRecord {
463     pub eye_catcher: String,
464     pub weight_index: Option<usize>,
465     pub n_cases: Option<u64>,
466     pub creation: NaiveDateTime,
467     pub file_label: String,
468 }
469
470 fn trim_end_spaces(mut s: String) -> String {
471     s.truncate(s.trim_end_matches(' ').len());
472     s
473 }
474
475 impl TryDecode for HeaderRecord {
476     type Input = crate::raw::HeaderRecord;
477
478     fn try_decode(
479         decoder: &mut Decoder,
480         input: &Self::Input,
481         warn: impl Fn(Error),
482     ) -> Result<Option<Self>, Error> {
483         let eye_catcher = trim_end_spaces(decoder.decode_string(&input.eye_catcher.0, &warn));
484         let file_label = trim_end_spaces(decoder.decode_string(&input.file_label.0, &warn));
485         let creation_date = decoder.decode_string_cow(&input.creation_date.0, &warn);
486         let creation_date =
487             NaiveDate::parse_from_str(&creation_date, "%e %b %Y").unwrap_or_else(|_| {
488                 warn(Error::InvalidCreationDate {
489                     creation_date: creation_date.into(),
490                 });
491                 Default::default()
492             });
493         let creation_time = decoder.decode_string_cow(&input.creation_time.0, &warn);
494         let creation_time =
495             NaiveTime::parse_from_str(&creation_time, "%H:%M:%S").unwrap_or_else(|_| {
496                 warn(Error::InvalidCreationTime {
497                     creation_time: creation_time.into(),
498                 });
499                 Default::default()
500             });
501         Ok(Some(HeaderRecord {
502             eye_catcher,
503             weight_index: input.weight_index.map(|n| n as usize),
504             n_cases: input.n_cases.map(|n| n as u64),
505             creation: NaiveDateTime::new(creation_date, creation_time),
506             file_label,
507         }))
508     }
509 }
510
511 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
512 pub enum VarWidth {
513     Numeric,
514     String(u16),
515 }
516
517 impl PartialOrd for VarWidth {
518     fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
519         match (self, other) {
520             (VarWidth::Numeric, VarWidth::Numeric) => Some(Ordering::Equal),
521             (VarWidth::String(a), VarWidth::String(b)) => Some(a.cmp(b)),
522             _ => None,
523         }
524     }
525 }
526
527 impl VarWidth {
528     const MAX_STRING: u16 = 32767;
529
530     fn n_dict_indexes(self) -> usize {
531         match self {
532             VarWidth::Numeric => 1,
533             VarWidth::String(w) => div_ceil(w as usize, 8),
534         }
535     }
536
537     fn width_predicate(
538         a: Option<VarWidth>,
539         b: Option<VarWidth>,
540         f: impl Fn(u16, u16) -> u16,
541     ) -> Option<VarWidth> {
542         match (a, b) {
543             (Some(VarWidth::Numeric), Some(VarWidth::Numeric)) => Some(VarWidth::Numeric),
544             (Some(VarWidth::String(a)), Some(VarWidth::String(b))) => {
545                 Some(VarWidth::String(f(a, b)))
546             }
547             _ => None,
548         }
549     }
550
551     /// Returns the wider of `self` and `other`:
552     /// - Numerical variable widths are equally wide.
553     /// - Longer strings are wider than shorter strings.
554     /// - Numerical and string types are incomparable, so result in `None`.
555     /// - Any `None` in the input yields `None` in the output.
556     pub fn wider(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
557         Self::width_predicate(a, b, |a, b| a.max(b))
558     }
559
560     /// Returns the narrower of `self` and `other` (see [`Self::wider`]).
561     pub fn narrower(a: Option<VarWidth>, b: Option<VarWidth>) -> Option<VarWidth> {
562         Self::width_predicate(a, b, |a, b| a.min(b))
563     }
564 }
565
566 impl From<VarWidth> for VarType {
567     fn from(source: VarWidth) -> Self {
568         match source {
569             VarWidth::Numeric => VarType::Numeric,
570             VarWidth::String(_) => VarType::String,
571         }
572     }
573 }
574
575 #[derive(Clone, Debug)]
576 pub struct VariableRecord {
577     pub width: VarWidth,
578     pub name: Identifier,
579     pub print_format: Spec,
580     pub write_format: Spec,
581     pub missing_values: MissingValues,
582     pub label: Option<String>,
583 }
584
585 fn decode_format(raw: raw::Spec, width: VarWidth, warn: impl Fn(Spec, FormatError)) -> Spec {
586     UncheckedSpec::try_from(raw)
587         .and_then(Spec::try_from)
588         .and_then(|x| x.check_width_compatibility(width))
589         .unwrap_or_else(|error| {
590             let new_format = Spec::default_for_width(width);
591             warn(new_format, error);
592             new_format
593         })
594 }
595
596 impl TryDecode for VariableRecord {
597     type Input = raw::VariableRecord;
598
599     fn try_decode(
600         decoder: &mut Decoder,
601         input: &crate::raw::VariableRecord,
602         warn: impl Fn(Error),
603     ) -> Result<Option<VariableRecord>, Error> {
604         let width = match input.width {
605             0 => VarWidth::Numeric,
606             w @ 1..=255 => VarWidth::String(w as u16),
607             -1 => return Ok(None),
608             _ => {
609                 return Err(Error::InvalidVariableWidth {
610                     offset: input.offset,
611                     width: input.width,
612                 })
613             }
614         };
615         let name = trim_end_spaces(decoder.decode_string(&input.name.0, &warn));
616         let name = match Identifier::new(&name, decoder.encoding) {
617             Ok(name) => {
618                 if !decoder.var_names.contains_key(&name) {
619                     name
620                 } else {
621                     let new_name = decoder.generate_name();
622                     warn(Error::DuplicateVariableName {
623                         duplicate_name: name.clone(),
624                         new_name: new_name.clone(),
625                     });
626                     new_name
627                 }
628             }
629             Err(id_error) => {
630                 let new_name = decoder.generate_name();
631                 warn(Error::InvalidVariableName {
632                     id_error,
633                     new_name: new_name.clone(),
634                 });
635                 new_name
636             }
637         };
638         let variable = Variable {
639             dict_index: decoder.n_dict_indexes,
640             short_name: name.clone(),
641             long_name: None,
642             width,
643         };
644         decoder.n_dict_indexes += width.n_dict_indexes();
645         assert!(decoder
646             .var_names
647             .insert(name.clone(), variable.dict_index)
648             .is_none());
649         assert!(decoder
650             .variables
651             .insert(variable.dict_index, variable)
652             .is_none());
653
654         let print_format = decode_format(input.print_format, width, |new_spec, format_error| {
655             warn(Error::InvalidPrintFormat {
656                 new_spec,
657                 variable: name.clone(),
658                 format_error,
659             })
660         });
661         let write_format = decode_format(input.write_format, width, |new_spec, format_error| {
662             warn(Error::InvalidWriteFormat {
663                 new_spec,
664                 variable: name.clone(),
665                 format_error,
666             })
667         });
668         let label = input
669             .label
670             .as_ref()
671             .map(|label| decoder.decode_string(&label.0, &warn));
672         Ok(Some(VariableRecord {
673             width,
674             name,
675             print_format,
676             write_format,
677             missing_values: input.missing_values.clone(),
678             label,
679         }))
680     }
681 }
682
683 #[derive(Clone, Debug)]
684 pub struct DocumentRecord(Vec<String>);
685
686 impl TryDecode for DocumentRecord {
687     type Input = crate::raw::DocumentRecord;
688
689     fn try_decode(
690         decoder: &mut Decoder,
691         input: &Self::Input,
692         warn: impl Fn(Error),
693     ) -> Result<Option<Self>, Error> {
694         Ok(Some(DocumentRecord(
695             input
696                 .lines
697                 .iter()
698                 .map(|s| trim_end_spaces(decoder.decode_string(&s.0, &warn)))
699                 .collect(),
700         )))
701     }
702 }
703
704 trait TextRecord
705 where
706     Self: Sized,
707 {
708     const NAME: &'static str;
709     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error>;
710 }
711
712 #[derive(Clone, Debug)]
713 pub struct VariableSet {
714     pub name: String,
715     pub vars: Vec<String>,
716 }
717
718 impl VariableSet {
719     fn parse(input: &str) -> Result<Self, Error> {
720         let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
721         let vars = input.split_ascii_whitespace().map(String::from).collect();
722         Ok(VariableSet {
723             name: name.into(),
724             vars,
725         })
726     }
727 }
728
729 trait WarnOnError<T> {
730     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
731 }
732 impl<T> WarnOnError<T> for Result<T, Error> {
733     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
734         match self {
735             Ok(result) => Some(result),
736             Err(error) => {
737                 warn(error);
738                 None
739             }
740         }
741     }
742 }
743
744 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
745 pub enum Value {
746     Number(Option<OrderedFloat<f64>>),
747     String(String),
748 }
749
750 impl Value {
751     pub fn decode(raw: raw::Value, decoder: &Decoder) -> Self {
752         match raw {
753             raw::Value::Number(x) => Value::Number(x.map(|x| x.into())),
754             raw::Value::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
755         }
756     }
757 }
758
759 #[derive(Clone, Debug)]
760 pub struct ValueLabel {
761     pub value: Value,
762     pub label: String,
763 }
764
765 #[derive(Clone, Debug)]
766 pub struct ValueLabelRecord {
767     pub var_type: VarType,
768     pub labels: Vec<ValueLabel>,
769     pub variables: Vec<Identifier>,
770 }
771
772 impl TryDecode for ValueLabelRecord {
773     type Input = crate::raw::ValueLabelRecord;
774     fn try_decode(
775         decoder: &mut Decoder,
776         input: &Self::Input,
777         warn: impl Fn(Error),
778     ) -> Result<Option<ValueLabelRecord>, Error> {
779         let variables: Vec<&Variable> = input
780             .dict_indexes
781             .iter()
782             .filter_map(|&dict_index| {
783                 decoder
784                     .get_var_by_index(dict_index as usize)
785                     .warn_on_error(&warn)
786             })
787             .filter(|&variable| match variable.width {
788                 VarWidth::String(width) if width > 8 => {
789                     warn(Error::InvalidLongStringValueLabel(
790                         variable.short_name.clone(),
791                     ));
792                     false
793                 }
794                 _ => true,
795             })
796             .collect();
797         let mut i = variables.iter();
798         let Some(&first_var) = i.next() else {
799             return Ok(None);
800         };
801         let var_type: VarType = first_var.width.into();
802         for &variable in i {
803             let this_type: VarType = variable.width.into();
804             if var_type != this_type {
805                 let (numeric_var, string_var) = match var_type {
806                     VarType::Numeric => (first_var, variable),
807                     VarType::String => (variable, first_var),
808                 };
809                 warn(Error::ValueLabelsDifferentTypes {
810                     numeric_var: numeric_var.short_name.clone(),
811                     string_var: string_var.short_name.clone(),
812                 });
813                 return Ok(None);
814             }
815         }
816         let labels = input
817             .labels
818             .iter()
819             .map(|(value, label)| {
820                 let label = decoder.decode_string(&label.0, &warn);
821                 let value = Value::decode(
822                     raw::Value::from_raw(*value, var_type, decoder.endian),
823                     &decoder,
824                 );
825                 ValueLabel { value, label }
826             })
827             .collect();
828         let variables = variables
829             .iter()
830             .map(|&variable| variable.short_name.clone())
831             .collect();
832         Ok(Some(ValueLabelRecord {
833             var_type,
834             labels,
835             variables,
836         }))
837     }
838 }
839
840 #[derive(Clone, Debug)]
841 pub struct VariableSetRecord(Vec<VariableSet>);
842
843 impl TextRecord for VariableSetRecord {
844     const NAME: &'static str = "variable set";
845     fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
846         let mut sets = Vec::new();
847         for line in input.lines() {
848             if let Some(set) = VariableSet::parse(line).warn_on_error(&warn) {
849                 sets.push(set)
850             }
851         }
852         Ok(VariableSetRecord(sets))
853     }
854 }
855
856 #[derive(Clone, Debug)]
857 pub struct ProductInfoRecord(pub String);
858
859 impl TextRecord for ProductInfoRecord {
860     const NAME: &'static str = "extra product info";
861     fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
862         Ok(ProductInfoRecord(input.into()))
863     }
864 }
865
866 #[derive(Clone, Debug)]
867 pub struct LongName {
868     pub short_name: Identifier,
869     pub long_name: Identifier,
870 }
871
872 impl LongName {
873     fn new(decoder: &mut Decoder, short_name: &str, long_name: &str) -> Result<LongName, Error> {
874         let short_name = Identifier::new(short_name, decoder.encoding)
875             .map_err(|e| Error::InvalidShortName(e))?;
876         let long_name =
877             Identifier::new(long_name, decoder.encoding).map_err(|e| Error::InvalidLongName(e))?;
878         Ok(LongName {
879             short_name,
880             long_name,
881         })
882     }
883 }
884
885 #[derive(Clone, Debug)]
886 pub struct LongNameRecord(Vec<LongName>);
887
888 impl LongNameRecord {
889     pub fn parse(decoder: &mut Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
890         let mut names = Vec::new();
891         for pair in input.split('\t').filter(|s| !s.is_empty()) {
892             if let Some((short_name, long_name)) = pair.split_once('=') {
893                 if let Some(long_name) =
894                     LongName::new(decoder, short_name, long_name).warn_on_error(&warn)
895                 {
896                     names.push(long_name);
897                 }
898             } else {
899                 warn(Error::TBD)
900             }
901         }
902         Ok(LongNameRecord(names))
903     }
904 }
905
906 #[derive(Clone, Debug)]
907 pub struct VeryLongString {
908     pub short_name: Identifier,
909     pub length: u16,
910 }
911
912 impl VeryLongString {
913     fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Error> {
914         let Some((short_name, length)) = input.split_once('=') else {
915             return Err(Error::TBD);
916         };
917         let short_name = Identifier::new(short_name, decoder.encoding)
918             .map_err(|e| Error::InvalidLongStringName(e))?;
919         let length: u16 = length.parse().map_err(|_| Error::TBD)?;
920         if length > VarWidth::MAX_STRING {
921             return Err(Error::TBD);
922         }
923         Ok(VeryLongString {
924             short_name: short_name.into(),
925             length,
926         })
927     }
928 }
929
930 #[derive(Clone, Debug)]
931 pub struct VeryLongStringRecord(Vec<VeryLongString>);
932
933 impl VeryLongStringRecord {
934     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
935         let mut very_long_strings = Vec::new();
936         for tuple in input
937             .split('\0')
938             .map(|s| s.trim_end_matches('\t'))
939             .filter(|s| !s.is_empty())
940         {
941             if let Some(vls) = VeryLongString::parse(decoder, tuple).warn_on_error(&warn) {
942                 very_long_strings.push(vls)
943             }
944         }
945         Ok(VeryLongStringRecord(very_long_strings))
946     }
947 }
948
949 #[derive(Clone, Debug)]
950 pub struct Attribute {
951     pub name: Identifier,
952     pub values: Vec<String>,
953 }
954
955 impl Attribute {
956     fn parse<'a>(
957         decoder: &Decoder,
958         input: &'a str,
959         warn: &impl Fn(Error),
960     ) -> Result<(Option<Attribute>, &'a str), Error> {
961         let Some((name, mut input)) = input.split_once('(') else {
962             return Err(Error::TBD);
963         };
964         let mut values = Vec::new();
965         loop {
966             let Some((value, rest)) = input.split_once('\n') else {
967                 return Err(Error::TBD);
968             };
969             if let Some(stripped) = value
970                 .strip_prefix('\'')
971                 .and_then(|value| value.strip_suffix('\''))
972             {
973                 values.push(stripped.into());
974             } else {
975                 warn(Error::TBD);
976                 values.push(value.into());
977             }
978             if let Some(rest) = rest.strip_prefix(')') {
979                 let attribute = Identifier::new(name, decoder.encoding)
980                     .map_err(|e| Error::InvalidAttributeName(e))
981                     .warn_on_error(warn)
982                     .map(|name| Attribute { name, values });
983                 return Ok((attribute, rest));
984             };
985             input = rest;
986         }
987     }
988 }
989
990 #[derive(Clone, Debug)]
991 pub struct AttributeSet(pub Vec<Attribute>);
992
993 impl AttributeSet {
994     fn parse<'a>(
995         decoder: &Decoder,
996         mut input: &'a str,
997         sentinel: Option<char>,
998         warn: &impl Fn(Error),
999     ) -> Result<(AttributeSet, &'a str), Error> {
1000         let mut attributes = Vec::new();
1001         let rest = loop {
1002             match input.chars().next() {
1003                 None => break input,
1004                 c if c == sentinel => break &input[1..],
1005                 _ => {
1006                     let (attribute, rest) = Attribute::parse(decoder, input, &warn)?;
1007                     if let Some(attribute) = attribute {
1008                         attributes.push(attribute);
1009                     }
1010                     input = rest;
1011                 }
1012             }
1013         };
1014         Ok((AttributeSet(attributes), rest))
1015     }
1016 }
1017
1018 #[derive(Clone, Debug)]
1019 pub struct FileAttributeRecord(AttributeSet);
1020
1021 impl FileAttributeRecord {
1022     pub fn parse(decoder: &Decoder, input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1023         let (set, rest) = AttributeSet::parse(decoder, input, None, &warn)?;
1024         if !rest.is_empty() {
1025             warn(Error::TBD);
1026         }
1027         Ok(FileAttributeRecord(set))
1028     }
1029 }
1030
1031 #[derive(Clone, Debug)]
1032 pub struct VarAttributeSet {
1033     pub long_var_name: Identifier,
1034     pub attributes: AttributeSet,
1035 }
1036
1037 impl VarAttributeSet {
1038     fn parse<'a>(
1039         decoder: &Decoder,
1040         input: &'a str,
1041         warn: &impl Fn(Error),
1042     ) -> Result<(Option<VarAttributeSet>, &'a str), Error> {
1043         let Some((long_var_name, rest)) = input.split_once(':') else {
1044             return Err(Error::TBD);
1045         };
1046         let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'), warn)?;
1047         let var_attribute = Identifier::new(long_var_name, decoder.encoding)
1048             .map_err(|e| Error::InvalidAttributeVariableName(e))
1049             .warn_on_error(warn)
1050             .map(|name| VarAttributeSet {
1051                 long_var_name: name,
1052                 attributes,
1053             });
1054         Ok((var_attribute, rest))
1055     }
1056 }
1057
1058 #[derive(Clone, Debug)]
1059 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
1060
1061 impl VariableAttributeRecord {
1062     pub fn parse(decoder: &Decoder, mut input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1063         let mut var_attribute_sets = Vec::new();
1064         while !input.is_empty() {
1065             let Some((var_attribute, rest)) =
1066                 VarAttributeSet::parse(decoder, input, &warn).warn_on_error(&warn)
1067             else {
1068                 break;
1069             };
1070             if let Some(var_attribute) = var_attribute {
1071                 var_attribute_sets.push(var_attribute);
1072             }
1073             input = rest;
1074         }
1075         Ok(VariableAttributeRecord(var_attribute_sets))
1076     }
1077 }
1078
1079 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1080 pub enum Measure {
1081     Nominal,
1082     Ordinal,
1083     Scale,
1084 }
1085
1086 impl Measure {
1087     fn try_decode(source: u32) -> Result<Option<Measure>, Error> {
1088         match source {
1089             0 => Ok(None),
1090             1 => Ok(Some(Measure::Nominal)),
1091             2 => Ok(Some(Measure::Ordinal)),
1092             3 => Ok(Some(Measure::Scale)),
1093             _ => Err(Error::InvalidMeasurement(source)),
1094         }
1095     }
1096 }
1097
1098 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1099 pub enum Alignment {
1100     Left,
1101     Right,
1102     Center,
1103 }
1104
1105 impl Alignment {
1106     fn try_decode(source: u32) -> Result<Option<Alignment>, Error> {
1107         match source {
1108             0 => Ok(None),
1109             1 => Ok(Some(Alignment::Left)),
1110             2 => Ok(Some(Alignment::Right)),
1111             3 => Ok(Some(Alignment::Center)),
1112             _ => Err(Error::InvalidAlignment(source)),
1113         }
1114     }
1115 }
1116
1117 #[derive(Clone, Debug)]
1118 pub struct VarDisplay {
1119     pub measure: Option<Measure>,
1120     pub width: Option<u32>,
1121     pub alignment: Option<Alignment>,
1122 }
1123
1124 #[derive(Clone, Debug)]
1125 pub struct VarDisplayRecord(pub Vec<VarDisplay>);
1126
1127 impl TryDecode for VarDisplayRecord {
1128     type Input = raw::VarDisplayRecord;
1129     fn try_decode(
1130         decoder: &mut Decoder,
1131         input: &Self::Input,
1132         warn: impl Fn(Error),
1133     ) -> Result<Option<Self>, Error> {
1134         let n_vars = decoder.variables.len();
1135         let n_per_var = if input.0.len() == 3 * n_vars {
1136             3
1137         } else if input.0.len() == 2 * n_vars {
1138             2
1139         } else {
1140             return Err(Error::TBD);
1141         };
1142
1143         let var_displays = input
1144             .0
1145             .chunks(n_per_var)
1146             .map(|chunk| {
1147                 let (measure, width, alignment) = match n_per_var == 3 {
1148                     true => (chunk[0], Some(chunk[1]), chunk[2]),
1149                     false => (chunk[0], None, chunk[1]),
1150                 };
1151                 let measure = Measure::try_decode(measure).warn_on_error(&warn).flatten();
1152                 let alignment = Alignment::try_decode(alignment)
1153                     .warn_on_error(&warn)
1154                     .flatten();
1155                 VarDisplay {
1156                     measure,
1157                     width,
1158                     alignment,
1159                 }
1160             })
1161             .collect();
1162         Ok(Some(VarDisplayRecord(var_displays)))
1163     }
1164 }
1165
1166 #[derive(Clone, Debug)]
1167 pub enum MultipleResponseType {
1168     MultipleDichotomy {
1169         value: Value,
1170         labels: CategoryLabels,
1171     },
1172     MultipleCategory,
1173 }
1174
1175 impl MultipleResponseType {
1176     fn decode(
1177         decoder: &Decoder,
1178         mr_set: &Identifier,
1179         input: &raw::MultipleResponseType,
1180         min_width: VarWidth,
1181         warn: &impl Fn(Error),
1182     ) -> Result<Self, Error> {
1183         let mr_type = match input {
1184             raw::MultipleResponseType::MultipleDichotomy { value, labels } => {
1185                 let value = decoder.decode_string_cow(&value.0, warn);
1186                 let value = match min_width {
1187                     VarWidth::Numeric => {
1188                         let number: f64 = value.trim().parse().map_err(|_| {
1189                             Error::InvalidMDGroupCountedValue {
1190                                 mr_set: mr_set.clone(),
1191                                 number: value.into(),
1192                             }
1193                         })?;
1194                         Value::Number(Some(number.into()))
1195                     }
1196                     VarWidth::String(max_width) => {
1197                         let value = value.trim_end_matches(' ');
1198                         let width = value.len();
1199                         if width > max_width as usize {
1200                             return Err(Error::TooWideMDGroupCountedValue {
1201                                 mr_set: mr_set.clone(),
1202                                 value: value.into(),
1203                                 width,
1204                                 max_width,
1205                             });
1206                         };
1207                         Value::String(value.into())
1208                     }
1209                 };
1210                 MultipleResponseType::MultipleDichotomy {
1211                     value,
1212                     labels: *labels,
1213                 }
1214             }
1215             raw::MultipleResponseType::MultipleCategory => MultipleResponseType::MultipleCategory,
1216         };
1217         Ok(mr_type)
1218     }
1219 }
1220
1221 #[derive(Clone, Debug)]
1222 pub struct MultipleResponseSet {
1223     pub name: Identifier,
1224     pub min_width: VarWidth,
1225     pub max_width: VarWidth,
1226     pub label: String,
1227     pub mr_type: MultipleResponseType,
1228     pub dict_indexes: Vec<DictIndex>,
1229 }
1230
1231 impl MultipleResponseSet {
1232     fn decode(
1233         decoder: &Decoder,
1234         input: &raw::MultipleResponseSet,
1235         warn: &impl Fn(Error),
1236     ) -> Result<Self, Error> {
1237         let mr_set_name = decoder
1238             .decode_identifier(&input.name.0, warn)
1239             .map_err(|error| Error::InvalidMrSetName(error))?;
1240
1241         let label = decoder.decode_string(&input.label.0, warn);
1242
1243         let mut dict_indexes = Vec::with_capacity(input.short_names.len());
1244         for short_name in input.short_names.iter() {
1245             let short_name = match decoder.decode_identifier(&short_name.0, warn) {
1246                 Ok(name) => name,
1247                 Err(error) => {
1248                     warn(Error::InvalidMrSetName(error));
1249                     continue;
1250                 }
1251             };
1252             let Some(&dict_index) = decoder.var_names.get(&short_name) else {
1253                 warn(Error::UnknownMrSetVariable {
1254                     mr_set: mr_set_name.clone(),
1255                     short_name: short_name.clone(),
1256                 });
1257                 continue;
1258             };
1259             dict_indexes.push(dict_index);
1260         }
1261
1262         match dict_indexes.len() {
1263             0 => return Err(Error::EmptyMrSet(mr_set_name)),
1264             1 => return Err(Error::OneVarMrSet(mr_set_name)),
1265             _ => (),
1266         }
1267
1268         let Some((Some(min_width), Some(max_width))) = dict_indexes
1269             .iter()
1270             .map(|dict_index| decoder.variables[dict_index].width)
1271             .map(|w| (Some(w), Some(w)))
1272             .reduce(|(na, wa), (nb, wb)| (VarWidth::narrower(na, nb), VarWidth::wider(wa, wb)))
1273         else {
1274             return Err(Error::MixedMrSet(mr_set_name));
1275         };
1276
1277         let mr_type =
1278             MultipleResponseType::decode(decoder, &mr_set_name, &input.mr_type, min_width, warn)?;
1279
1280         Ok(MultipleResponseSet {
1281             name: mr_set_name,
1282             min_width,
1283             max_width,
1284             label,
1285             mr_type,
1286             dict_indexes,
1287         })
1288     }
1289 }
1290
1291 #[derive(Clone, Debug)]
1292 pub struct MultipleResponseRecord(pub Vec<MultipleResponseSet>);
1293
1294 impl TryDecode for MultipleResponseRecord {
1295     type Input = raw::MultipleResponseRecord;
1296
1297     fn try_decode(
1298         decoder: &mut Decoder,
1299         input: &Self::Input,
1300         warn: impl Fn(Error),
1301     ) -> Result<Option<Self>, Error> {
1302         let mut sets = Vec::with_capacity(input.0.len());
1303         for set in &input.0 {
1304             match MultipleResponseSet::decode(decoder, set, &warn) {
1305                 Ok(set) => sets.push(set),
1306                 Err(error) => warn(error),
1307             }
1308         }
1309         Ok(Some(MultipleResponseRecord(sets)))
1310     }
1311 }
1312
1313 #[derive(Clone, Debug)]
1314 pub struct LongStringValueLabels {
1315     pub var_name: Identifier,
1316     pub width: VarWidth,
1317     pub labels: Vec<ValueLabel>,
1318 }
1319
1320 impl LongStringValueLabels {
1321     fn decode(
1322         decoder: &Decoder,
1323         input: &raw::LongStringValueLabels,
1324         warn: &impl Fn(Error),
1325     ) -> Result<Self, Error> {
1326         let var_name = decoder.decode_string(&input.var_name.0, warn);
1327         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
1328             .map_err(|e| Error::InvalidLongStringValueLabelName(e))?;
1329
1330         let min_width = 9;
1331         let max_width = VarWidth::MAX_STRING;
1332         if input.width < 9 || input.width > max_width as u32 {
1333             return Err(Error::InvalidLongValueLabelWidth {
1334                 name: var_name.into(),
1335                 width: input.width,
1336                 min_width,
1337                 max_width,
1338             });
1339         }
1340         let width = input.width as u16;
1341
1342         let mut labels = Vec::with_capacity(input.labels.len());
1343         for (value, label) in input.labels.iter() {
1344             let value = Value::String(decoder.decode_exact_length(&value.0).into());
1345             let label = decoder.decode_string(&label.0, warn);
1346             labels.push(ValueLabel { value, label });
1347         }
1348
1349         Ok(LongStringValueLabels {
1350             var_name,
1351             width: VarWidth::String(width),
1352             labels,
1353         })
1354     }
1355 }
1356
1357 #[derive(Clone, Debug)]
1358 pub struct LongStringValueLabelRecord(pub Vec<LongStringValueLabels>);
1359
1360 impl TryDecode for LongStringValueLabelRecord {
1361     type Input = raw::LongStringValueLabelRecord;
1362
1363     fn try_decode(
1364         decoder: &mut Decoder,
1365         input: &Self::Input,
1366         warn: impl Fn(Error),
1367     ) -> Result<Option<Self>, Error> {
1368         let mut labels = Vec::with_capacity(input.0.len());
1369         for label in &input.0 {
1370             match LongStringValueLabels::decode(decoder, label, &warn) {
1371                 Ok(set) => labels.push(set),
1372                 Err(error) => warn(error),
1373             }
1374         }
1375         Ok(Some(LongStringValueLabelRecord(labels)))
1376     }
1377 }
1378
1379 #[cfg(test)]
1380 mod test {
1381     use encoding_rs::WINDOWS_1252;
1382
1383     #[test]
1384     fn test() {
1385         let mut s = String::new();
1386         s.push(char::REPLACEMENT_CHARACTER);
1387         let encoded = WINDOWS_1252.encode(&s).0;
1388         let decoded = WINDOWS_1252.decode(&encoded[..]).0;
1389         println!("{:?}", decoded);
1390     }
1391
1392     #[test]
1393     fn test2() {
1394         let charset: Vec<u8> = (0..=255).collect();
1395         println!("{}", charset.len());
1396         let decoded = WINDOWS_1252.decode(&charset[..]).0;
1397         println!("{}", decoded.len());
1398         let encoded = WINDOWS_1252.encode(&decoded[..]).0;
1399         println!("{}", encoded.len());
1400         assert_eq!(&charset[..], &encoded[..]);
1401     }
1402 }