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