1a760a0517dc26168b6084be90266fb7227f8007
[pspp] / rust / src / raw.rs
1 use crate::{
2     dictionary::VarWidth,
3     encoding::{default_encoding, get_encoding, Error as EncodingError},
4     endian::{Endian, Parse, ToBytes},
5     identifier::{Error as IdError, Identifier},
6 };
7
8 use encoding_rs::{mem::decode_latin1, DecoderResult, Encoding};
9 use flate2::read::ZlibDecoder;
10 use num::Integer;
11 use std::{
12     borrow::Cow,
13     cell::RefCell,
14     cmp::Ordering,
15     collections::{HashMap, VecDeque},
16     fmt::{Debug, Display, Formatter, Result as FmtResult},
17     io::{Error as IoError, Read, Seek, SeekFrom},
18     iter::repeat,
19     mem::take,
20     ops::Range,
21     rc::Rc,
22     str::from_utf8,
23 };
24 use thiserror::Error as ThisError;
25
26 #[derive(ThisError, Debug)]
27 pub enum Error {
28     #[error("Not an SPSS system file")]
29     NotASystemFile,
30
31     #[error("Invalid magic number {0:?}")]
32     BadMagic([u8; 4]),
33
34     #[error("I/O error ({0})")]
35     Io(#[from] IoError),
36
37     #[error("Invalid SAV compression code {0}")]
38     InvalidSavCompression(u32),
39
40     #[error("Invalid ZSAV compression code {0}")]
41     InvalidZsavCompression(u32),
42
43     #[error("Document record at offset {offset:#x} has document line count ({n}) greater than the maximum number {max}.")]
44     BadDocumentLength { offset: u64, n: usize, max: usize },
45
46     #[error("At offset {offset:#x}, unrecognized record type {rec_type}.")]
47     BadRecordType { offset: u64, rec_type: u32 },
48
49     #[error("In variable record starting at offset {start_offset:#x}, variable label code {code} at offset {code_offset:#x} is not 0 or 1.")]
50     BadVariableLabelCode {
51         start_offset: u64,
52         code_offset: u64,
53         code: u32,
54     },
55
56     #[error(
57         "At offset {offset:#x}, numeric missing value code ({code}) is not -3, -2, 0, 1, 2, or 3."
58     )]
59     BadNumericMissingValueCode { offset: u64, code: i32 },
60
61     #[error("At offset {offset:#x}, string missing value code ({code}) is not 0, 1, 2, or 3.")]
62     BadStringMissingValueCode { offset: u64, code: i32 },
63
64     #[error("At offset {offset:#x}, number of value labels ({n}) is greater than the maximum number {max}.")]
65     BadNumberOfValueLabels { offset: u64, n: u32, max: u32 },
66
67     #[error("At offset {offset:#x}, following value label record, found record type {rec_type} instead of expected type 4 for variable index record")]
68     ExpectedVarIndexRecord { offset: u64, rec_type: u32 },
69
70     #[error("At offset {offset:#x}, number of variables indexes for value labels ({n}) is greater than the maximum number ({max}).")]
71     TooManyVarIndexes { offset: u64, n: u32, max: u32 },
72
73     #[error("At offset {offset:#x}, record type 7 subtype {subtype} is too large with element size {size} and {count} elements.")]
74     ExtensionRecordTooLarge {
75         offset: u64,
76         subtype: u32,
77         size: u32,
78         count: u32,
79     },
80
81     #[error("Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a {case_len}-byte case.")]
82     EofInCase {
83         offset: u64,
84         case_ofs: u64,
85         case_len: usize,
86     },
87
88     #[error(
89         "Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a compressed case."
90     )]
91     EofInCompressedCase { offset: u64, case_ofs: u64 },
92
93     #[error("Data ends at offset {offset:#x}, {case_ofs} bytes into a compressed case.")]
94     PartialCompressedCase { offset: u64, case_ofs: u64 },
95
96     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a string was found where a number was expected.")]
97     CompressedNumberExpected { offset: u64, case_ofs: u64 },
98
99     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a number was found where a string was expected.")]
100     CompressedStringExpected { offset: u64, case_ofs: u64 },
101
102     #[error("Block count {n_blocks} in ZLIB trailer at offset {offset:#x} differs from expected block count {expected_n_blocks} calculated from trailer length {ztrailer_len}.")]
103     BadZlibTrailerNBlocks {
104         offset: u64,
105         n_blocks: u32,
106         expected_n_blocks: u64,
107         ztrailer_len: u64,
108     },
109
110     #[error("{0}")]
111     EncodingError(EncodingError),
112 }
113
114 #[derive(ThisError, Debug)]
115 pub enum Warning {
116     #[error("Unexpected end of data inside extension record.")]
117     UnexpectedEndOfData,
118
119     #[error("At offset {offset:#x}, at least one valid variable index for value labels is required but none were specified.")]
120     NoVarIndexes { offset: u64 },
121
122     #[error("At offset {offset:#x}, the first variable index is for a {var_type} variable but the following variable indexes are for {} variables: {wrong_types:?}", var_type.opposite())]
123     MixedVarTypes {
124         offset: u64,
125         var_type: VarType,
126         wrong_types: Vec<u32>,
127     },
128
129     #[error("At offset {offset:#x}, one or more variable indexes for value labels were not in the valid range [1,{max}]: {invalid:?}")]
130     InvalidVarIndexes {
131         offset: u64,
132         max: usize,
133         invalid: Vec<u32>,
134     },
135
136     #[error("At offset {offset:#x}, {record} has bad size {size} bytes instead of the expected {expected_size}.")]
137     BadRecordSize {
138         offset: u64,
139         record: String,
140         size: u32,
141         expected_size: u32,
142     },
143
144     #[error("At offset {offset:#x}, {record} has bad count {count} instead of the expected {expected_count}.")]
145     BadRecordCount {
146         offset: u64,
147         record: String,
148         count: u32,
149         expected_count: u32,
150     },
151
152     #[error("In long string missing values record starting at offset {record_offset:#x}, value length at offset {offset:#x} is {value_len} instead of the expected 8.")]
153     BadLongMissingValueLength {
154         record_offset: u64,
155         offset: u64,
156         value_len: u32,
157     },
158
159     #[error("The encoding record at offset {offset:#x} contains an encoding name that is not valid UTF-8.")]
160     BadEncodingName { offset: u64 },
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("Invalid variable measurement level value {0}")]
167     InvalidMeasurement(u32),
168
169     #[error("Invalid variable display alignment value {0}")]
170     InvalidAlignment(u32),
171
172     #[error("Invalid attribute name.  {0}")]
173     InvalidAttributeName(IdError),
174
175     #[error("Invalid variable name in attribute record.  {0}")]
176     InvalidAttributeVariableName(IdError),
177
178     #[error("Invalid short name in long variable name record.  {0}")]
179     InvalidShortName(IdError),
180
181     #[error("Invalid name in long variable name record.  {0}")]
182     InvalidLongName(IdError),
183
184     #[error("Invalid variable name in very long string record.  {0}")]
185     InvalidLongStringName(IdError),
186
187     #[error("Invalid variable name in variable set record.  {0}")]
188     InvalidVariableSetName(IdError),
189
190     #[error("Invalid multiple response set name.  {0}")]
191     InvalidMrSetName(IdError),
192
193     #[error("Invalid multiple response set variable name.  {0}")]
194     InvalidMrSetVariableName(IdError),
195
196     #[error("Invalid variable name in long string missing values record.  {0}")]
197     InvalidLongStringMissingValueVariableName(IdError),
198
199     #[error("Invalid variable name in long string value label record.  {0}")]
200     InvalidLongStringValueLabelName(IdError),
201
202     #[error("{0}")]
203     EncodingError(EncodingError),
204
205     #[error("Details TBD")]
206     TBD,
207 }
208
209 impl From<IoError> for Warning {
210     fn from(_source: IoError) -> Self {
211         Self::UnexpectedEndOfData
212     }
213 }
214
215 #[derive(Clone, Debug)]
216 pub enum Record {
217     Header(HeaderRecord<RawString>),
218     Variable(VariableRecord<RawString, RawStr<8>>),
219     ValueLabel(ValueLabelRecord<RawStr<8>, RawString>),
220     Document(DocumentRecord<RawDocumentLine>),
221     IntegerInfo(IntegerInfoRecord),
222     FloatInfo(FloatInfoRecord),
223     VarDisplay(VarDisplayRecord),
224     MultipleResponse(MultipleResponseRecord<RawString, RawString>),
225     LongStringValueLabels(LongStringValueLabelRecord<RawString, RawString>),
226     LongStringMissingValues(LongStringMissingValueRecord<RawString, RawStr<8>>),
227     Encoding(EncodingRecord),
228     NumberOfCases(NumberOfCasesRecord),
229     Text(TextRecord),
230     OtherExtension(Extension),
231     EndOfHeaders(u32),
232     ZHeader(ZHeader),
233     ZTrailer(ZTrailer),
234     Cases(Rc<RefCell<Cases>>),
235 }
236
237 #[derive(Clone, Debug)]
238 pub enum DecodedRecord<'a> {
239     Header(HeaderRecord<Cow<'a, str>>),
240     Variable(VariableRecord<Cow<'a, str>, String>),
241     ValueLabel(ValueLabelRecord<RawStr<8>, Cow<'a, str>>),
242     Document(DocumentRecord<Cow<'a, str>>),
243     IntegerInfo(IntegerInfoRecord),
244     FloatInfo(FloatInfoRecord),
245     VarDisplay(VarDisplayRecord),
246     MultipleResponse(MultipleResponseRecord<Identifier, Cow<'a, str>>),
247     LongStringValueLabels(LongStringValueLabelRecord<Identifier, Cow<'a, str>>),
248     LongStringMissingValues(LongStringMissingValueRecord<Identifier, String>),
249     Encoding(EncodingRecord),
250     NumberOfCases(NumberOfCasesRecord),
251     VariableSets(VariableSetRecord),
252     ProductInfo(ProductInfoRecord),
253     LongNames(LongNamesRecord),
254     VeryLongStrings(VeryLongStringsRecord),
255     FileAttributes(FileAttributeRecord),
256     VariableAttributes(VariableAttributeRecord),
257     OtherExtension(Extension),
258     EndOfHeaders(u32),
259     ZHeader(ZHeader),
260     ZTrailer(ZTrailer),
261 }
262
263 impl Record {
264     fn read<R>(
265         reader: &mut R,
266         endian: Endian,
267         var_types: &[VarType],
268         warn: &dyn Fn(Warning),
269     ) -> Result<Option<Record>, Error>
270     where
271         R: Read + Seek,
272     {
273         let rec_type: u32 = endian.parse(read_bytes(reader)?);
274         match rec_type {
275             2 => Ok(Some(VariableRecord::read(reader, endian)?)),
276             3 => Ok(ValueLabelRecord::read(reader, endian, var_types, warn)?),
277             6 => Ok(Some(DocumentRecord::read(reader, endian)?)),
278             7 => Extension::read(reader, endian, var_types.len(), warn),
279             999 => Ok(Some(Record::EndOfHeaders(
280                 endian.parse(read_bytes(reader)?),
281             ))),
282             _ => Err(Error::BadRecordType {
283                 offset: reader.stream_position()?,
284                 rec_type,
285             }),
286         }
287     }
288
289     pub fn decode<'a>(&'a self, decoder: &Decoder) -> Result<DecodedRecord<'a>, Error> {
290         Ok(match self {
291             Record::Header(record) => record.decode(decoder),
292             Record::Variable(record) => record.decode(decoder),
293             Record::ValueLabel(record) => DecodedRecord::ValueLabel(record.decode(decoder)),
294             Record::Document(record) => record.decode(decoder),
295             Record::IntegerInfo(record) => DecodedRecord::IntegerInfo(record.clone()),
296             Record::FloatInfo(record) => DecodedRecord::FloatInfo(record.clone()),
297             Record::VarDisplay(record) => DecodedRecord::VarDisplay(record.clone()),
298             Record::MultipleResponse(record) => record.decode(decoder),
299             Record::LongStringValueLabels(record) => {
300                 DecodedRecord::LongStringValueLabels(record.decode(decoder))
301             }
302             Record::LongStringMissingValues(record) => {
303                 DecodedRecord::LongStringMissingValues(record.decode(decoder))
304             }
305             Record::Encoding(record) => DecodedRecord::Encoding(record.clone()),
306             Record::NumberOfCases(record) => DecodedRecord::NumberOfCases(record.clone()),
307             Record::Text(record) => record.decode(decoder),
308             Record::OtherExtension(record) => DecodedRecord::OtherExtension(record.clone()),
309             Record::EndOfHeaders(record) => DecodedRecord::EndOfHeaders(*record),
310             Record::ZHeader(record) => DecodedRecord::ZHeader(record.clone()),
311             Record::ZTrailer(record) => DecodedRecord::ZTrailer(record.clone()),
312             Record::Cases(_) => todo!(),
313         })
314     }
315 }
316
317 pub fn encoding_from_headers(
318     headers: &Vec<Record>,
319     warn: &impl Fn(Warning),
320 ) -> Result<&'static Encoding, Error> {
321     let mut encoding_record = None;
322     let mut integer_info_record = None;
323     for record in headers {
324         match record {
325             Record::Encoding(record) => encoding_record = Some(record),
326             Record::IntegerInfo(record) => integer_info_record = Some(record),
327             _ => (),
328         }
329     }
330     let encoding = encoding_record.map(|record| record.0.as_str());
331     let character_code = integer_info_record.map(|record| record.character_code);
332     match get_encoding(encoding, character_code) {
333         Ok(encoding) => Ok(encoding),
334         Err(err @ EncodingError::Ebcdic) => Err(Error::EncodingError(err)),
335         Err(err) => {
336             warn(Warning::EncodingError(err));
337             // Warn that we're using the default encoding.
338             Ok(default_encoding())
339         }
340     }
341 }
342
343 // If `s` is valid UTF-8, returns it decoded as UTF-8, otherwise returns it
344 // decoded as Latin-1 (actually bytes interpreted as Unicode code points).
345 fn default_decode(s: &[u8]) -> Cow<str> {
346     from_utf8(s).map_or_else(|_| decode_latin1(s), Cow::from)
347 }
348
349 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
350 pub enum Compression {
351     Simple,
352     ZLib,
353 }
354
355 trait Header {
356     fn offsets(&self) -> Range<u64>;
357 }
358
359 #[derive(Clone)]
360 pub struct HeaderRecord<S>
361 where
362     S: Debug,
363 {
364     /// Offset in file.
365     pub offsets: Range<u64>,
366
367     /// Magic number.
368     pub magic: Magic,
369
370     /// Eye-catcher string, product name, in the file's encoding.  Padded
371     /// on the right with spaces.
372     pub eye_catcher: S,
373
374     /// Layout code, normally either 2 or 3.
375     pub layout_code: u32,
376
377     /// Number of variable positions, or `None` if the value in the file is
378     /// questionably trustworthy.
379     pub nominal_case_size: Option<u32>,
380
381     /// Compression type, if any,
382     pub compression: Option<Compression>,
383
384     /// 1-based variable index of the weight variable, or `None` if the file is
385     /// unweighted.
386     pub weight_index: Option<u32>,
387
388     /// Claimed number of cases, if known.
389     pub n_cases: Option<u32>,
390
391     /// Compression bias, usually 100.0.
392     pub bias: f64,
393
394     /// `dd mmm yy` in the file's encoding.
395     pub creation_date: S,
396
397     /// `HH:MM:SS` in the file's encoding.
398     pub creation_time: S,
399
400     /// File label, in the file's encoding.  Padded on the right with spaces.
401     pub file_label: S,
402
403     /// Endianness of the data in the file header.
404     pub endian: Endian,
405 }
406
407 impl<S> HeaderRecord<S>
408 where
409     S: Debug,
410 {
411     fn debug_field<T>(&self, f: &mut Formatter, name: &str, value: T) -> FmtResult
412     where
413         T: Debug,
414     {
415         writeln!(f, "{name:>17}: {:?}", value)
416     }
417 }
418
419 impl<S> Debug for HeaderRecord<S>
420 where
421     S: Debug,
422 {
423     fn fmt(&self, f: &mut Formatter) -> FmtResult {
424         writeln!(f, "File header record:")?;
425         self.debug_field(f, "Magic", self.magic)?;
426         self.debug_field(f, "Product name", &self.eye_catcher)?;
427         self.debug_field(f, "Layout code", self.layout_code)?;
428         self.debug_field(f, "Nominal case size", self.nominal_case_size)?;
429         self.debug_field(f, "Compression", self.compression)?;
430         self.debug_field(f, "Weight index", self.weight_index)?;
431         self.debug_field(f, "Number of cases", self.n_cases)?;
432         self.debug_field(f, "Compression bias", self.bias)?;
433         self.debug_field(f, "Creation date", &self.creation_date)?;
434         self.debug_field(f, "Creation time", &self.creation_time)?;
435         self.debug_field(f, "File label", &self.file_label)?;
436         self.debug_field(f, "Endianness", self.endian)
437     }
438 }
439
440 impl HeaderRecord<RawString> {
441     fn read<R: Read + Seek>(r: &mut R) -> Result<Self, Error> {
442         let start = r.stream_position()?;
443
444         let magic: [u8; 4] = read_bytes(r)?;
445         let magic: Magic = magic.try_into().map_err(|_| Error::NotASystemFile)?;
446
447         let eye_catcher = RawString(read_vec(r, 60)?);
448         let layout_code: [u8; 4] = read_bytes(r)?;
449         let endian = Endian::identify_u32(2, layout_code)
450             .or_else(|| Endian::identify_u32(2, layout_code))
451             .ok_or_else(|| Error::NotASystemFile)?;
452         let layout_code = endian.parse(layout_code);
453
454         let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
455         let nominal_case_size =
456             (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
457
458         let compression_code: u32 = endian.parse(read_bytes(r)?);
459         let compression = match (magic, compression_code) {
460             (Magic::Zsav, 2) => Some(Compression::ZLib),
461             (Magic::Zsav, code) => return Err(Error::InvalidZsavCompression(code)),
462             (_, 0) => None,
463             (_, 1) => Some(Compression::Simple),
464             (_, code) => return Err(Error::InvalidSavCompression(code)),
465         };
466
467         let weight_index: u32 = endian.parse(read_bytes(r)?);
468         let weight_index = (weight_index > 0).then_some(weight_index);
469
470         let n_cases: u32 = endian.parse(read_bytes(r)?);
471         let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
472
473         let bias: f64 = endian.parse(read_bytes(r)?);
474
475         let creation_date = RawString(read_vec(r, 9)?);
476         let creation_time = RawString(read_vec(r, 8)?);
477         let file_label = RawString(read_vec(r, 64)?);
478         let _: [u8; 3] = read_bytes(r)?;
479
480         Ok(HeaderRecord {
481             offsets: start..r.stream_position()?,
482             magic,
483             layout_code,
484             nominal_case_size,
485             compression,
486             weight_index,
487             n_cases,
488             bias,
489             creation_date,
490             creation_time,
491             eye_catcher,
492             file_label,
493             endian,
494         })
495     }
496
497     pub fn decode<'a>(&'a self, decoder: &Decoder) -> DecodedRecord<'a> {
498         let eye_catcher = decoder.decode(&self.eye_catcher);
499         let file_label = decoder.decode(&self.file_label);
500         let creation_date = decoder.decode(&self.creation_date);
501         let creation_time = decoder.decode(&self.creation_time);
502         DecodedRecord::Header(HeaderRecord {
503             eye_catcher,
504             weight_index: self.weight_index,
505             n_cases: self.n_cases,
506             file_label,
507             offsets: self.offsets.clone(),
508             magic: self.magic,
509             layout_code: self.layout_code,
510             nominal_case_size: self.nominal_case_size,
511             compression: self.compression,
512             bias: self.bias,
513             creation_date,
514             creation_time,
515             endian: self.endian,
516         })
517     }
518 }
519
520 pub struct Decoder {
521     pub encoding: &'static Encoding,
522     pub warn: Box<dyn Fn(Warning)>,
523 }
524
525 impl Decoder {
526     pub fn new<F>(encoding: &'static Encoding, warn: F) -> Self
527     where
528         F: Fn(Warning) + 'static,
529     {
530         Self {
531             encoding,
532             warn: Box::new(warn),
533         }
534     }
535     fn warn(&self, warning: Warning) {
536         (self.warn)(warning)
537     }
538     fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
539         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
540         if malformed {
541             self.warn(Warning::MalformedString {
542                 encoding: self.encoding.name().into(),
543                 text: output.clone().into(),
544             });
545         }
546         output
547     }
548
549     fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
550         self.decode_slice(input.0.as_slice())
551     }
552
553     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
554     /// re-encoding the result back into `self.encoding` will have exactly the
555     /// same length in bytes.
556     ///
557     /// XXX warn about errors?
558     pub fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
559         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
560             // This is the common case.  Usually there will be no errors.
561             s
562         } else {
563             // Unusual case.  Don't bother to optimize it much.
564             let mut decoder = self.encoding.new_decoder_without_bom_handling();
565             let mut output = String::with_capacity(
566                 decoder
567                     .max_utf8_buffer_length_without_replacement(input.len())
568                     .unwrap(),
569             );
570             let mut rest = input;
571             while !rest.is_empty() {
572                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
573                     (DecoderResult::InputEmpty, _) => break,
574                     (DecoderResult::OutputFull, _) => unreachable!(),
575                     (DecoderResult::Malformed(a, b), consumed) => {
576                         let skipped = a as usize + b as usize;
577                         output.extend(repeat('?').take(skipped));
578                         rest = &rest[consumed..];
579                     }
580                 }
581             }
582             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
583             output.into()
584         }
585     }
586
587     pub fn decode_identifier(&self, input: &RawString) -> Result<Identifier, IdError> {
588         self.new_identifier(&self.decode(input))
589     }
590
591     pub fn new_identifier(&self, name: &str) -> Result<Identifier, IdError> {
592         Identifier::new(name, self.encoding)
593     }
594 }
595
596 impl<S> Header for HeaderRecord<S>
597 where
598     S: Debug,
599 {
600     fn offsets(&self) -> Range<u64> {
601         self.offsets.clone()
602     }
603 }
604
605 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
606 pub enum Magic {
607     /// Regular system file.
608     Sav,
609
610     /// System file with Zlib-compressed data.
611     Zsav,
612
613     /// EBCDIC-encoded system file.
614     Ebcdic,
615 }
616
617 impl Magic {
618     /// Magic number for a regular system file.
619     pub const SAV: [u8; 4] = *b"$FL2";
620
621     /// Magic number for a system file that contains zlib-compressed data.
622     pub const ZSAV: [u8; 4] = *b"$FL3";
623
624     /// Magic number for an EBCDIC-encoded system file.  This is `$FL2` encoded
625     /// in EBCDIC.
626     pub const EBCDIC: [u8; 4] = [0x5b, 0xc6, 0xd3, 0xf2];
627 }
628
629 impl Debug for Magic {
630     fn fmt(&self, f: &mut Formatter) -> FmtResult {
631         let s = match *self {
632             Magic::Sav => "$FL2",
633             Magic::Zsav => "$FL3",
634             Magic::Ebcdic => "($FL2 in EBCDIC)",
635         };
636         write!(f, "{s}")
637     }
638 }
639
640 impl TryFrom<[u8; 4]> for Magic {
641     type Error = Error;
642
643     fn try_from(value: [u8; 4]) -> Result<Self, Self::Error> {
644         match value {
645             Magic::SAV => Ok(Magic::Sav),
646             Magic::ZSAV => Ok(Magic::Zsav),
647             Magic::EBCDIC => Ok(Magic::Ebcdic),
648             _ => Err(Error::BadMagic(value)),
649         }
650     }
651 }
652
653 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
654 pub enum VarType {
655     Numeric,
656     String,
657 }
658
659 impl VarType {
660     pub fn from_width(width: VarWidth) -> VarType {
661         match width {
662             VarWidth::Numeric => Self::Numeric,
663             VarWidth::String(_) => Self::String,
664         }
665     }
666
667     pub fn opposite(self) -> VarType {
668         match self {
669             Self::Numeric => Self::String,
670             Self::String => Self::Numeric,
671         }
672     }
673 }
674
675 impl Display for VarType {
676     fn fmt(&self, f: &mut Formatter) -> FmtResult {
677         match self {
678             VarType::Numeric => write!(f, "numeric"),
679             VarType::String => write!(f, "string"),
680         }
681     }
682 }
683
684 #[derive(Copy, Clone)]
685 pub enum Value<S>
686 where
687     S: Debug,
688 {
689     Number(Option<f64>),
690     String(S),
691 }
692
693 type RawValue = Value<RawStr<8>>;
694
695 impl<S> Debug for Value<S>
696 where
697     S: Debug,
698 {
699     fn fmt(&self, f: &mut Formatter) -> FmtResult {
700         match self {
701             Value::Number(Some(number)) => write!(f, "{number:?}"),
702             Value::Number(None) => write!(f, "SYSMIS"),
703             Value::String(s) => write!(f, "{:?}", s),
704         }
705     }
706 }
707
708 impl RawValue {
709     fn read<R: Read>(r: &mut R, var_type: VarType, endian: Endian) -> Result<Self, IoError> {
710         Ok(Self::from_raw(
711             &UntypedValue(read_bytes(r)?),
712             var_type,
713             endian,
714         ))
715     }
716
717     pub fn from_raw(raw: &UntypedValue, var_type: VarType, endian: Endian) -> Self {
718         match var_type {
719             VarType::String => Value::String(RawStr(raw.0)),
720             VarType::Numeric => {
721                 let number: f64 = endian.parse(raw.0);
722                 Value::Number((number != -f64::MAX).then_some(number))
723             }
724         }
725     }
726
727     fn read_case<R: Read + Seek>(
728         reader: &mut R,
729         var_types: &[VarType],
730         endian: Endian,
731     ) -> Result<Option<Vec<Self>>, Error> {
732         let case_start = reader.stream_position()?;
733         let mut values = Vec::with_capacity(var_types.len());
734         for (i, &var_type) in var_types.iter().enumerate() {
735             let Some(raw) = try_read_bytes(reader)? else {
736                 if i == 0 {
737                     return Ok(None);
738                 } else {
739                     let offset = reader.stream_position()?;
740                     return Err(Error::EofInCase {
741                         offset,
742                         case_ofs: offset - case_start,
743                         case_len: var_types.len() * 8,
744                     });
745                 }
746             };
747             values.push(Value::from_raw(&UntypedValue(raw), var_type, endian));
748         }
749         Ok(Some(values))
750     }
751
752     fn read_compressed_case<R: Read + Seek>(
753         reader: &mut R,
754         var_types: &[VarType],
755         codes: &mut VecDeque<u8>,
756         endian: Endian,
757         bias: f64,
758     ) -> Result<Option<Vec<Self>>, Error> {
759         let case_start = reader.stream_position()?;
760         let mut values = Vec::with_capacity(var_types.len());
761         for (i, &var_type) in var_types.iter().enumerate() {
762             let value = loop {
763                 let Some(code) = codes.pop_front() else {
764                     let Some(new_codes): Option<[u8; 8]> = try_read_bytes(reader)? else {
765                         if i == 0 {
766                             return Ok(None);
767                         } else {
768                             let offset = reader.stream_position()?;
769                             return Err(Error::EofInCompressedCase {
770                                 offset,
771                                 case_ofs: offset - case_start,
772                             });
773                         }
774                     };
775                     codes.extend(new_codes.into_iter());
776                     continue;
777                 };
778                 match code {
779                     0 => (),
780                     1..=251 => match var_type {
781                         VarType::Numeric => break Self::Number(Some(code as f64 - bias)),
782                         VarType::String => {
783                             break Self::String(RawStr(endian.to_bytes(code as f64 - bias)))
784                         }
785                     },
786                     252 => {
787                         if i == 0 {
788                             return Ok(None);
789                         } else {
790                             let offset = reader.stream_position()?;
791                             return Err(Error::PartialCompressedCase {
792                                 offset,
793                                 case_ofs: offset - case_start,
794                             });
795                         }
796                     }
797                     253 => {
798                         break Self::from_raw(&UntypedValue(read_bytes(reader)?), var_type, endian)
799                     }
800                     254 => match var_type {
801                         VarType::String => break Self::String(RawStr(*b"        ")), // XXX EBCDIC
802                         VarType::Numeric => {
803                             return Err(Error::CompressedStringExpected {
804                                 offset: case_start,
805                                 case_ofs: reader.stream_position()? - case_start,
806                             })
807                         }
808                     },
809                     255 => match var_type {
810                         VarType::Numeric => break Self::Number(None),
811                         VarType::String => {
812                             return Err(Error::CompressedNumberExpected {
813                                 offset: case_start,
814                                 case_ofs: reader.stream_position()? - case_start,
815                             })
816                         }
817                     },
818                 }
819             };
820             values.push(value);
821         }
822         Ok(Some(values))
823     }
824
825     fn decode(&self, decoder: &Decoder) -> Value<String> {
826         match self {
827             Self::Number(x) => Value::Number(*x),
828             Self::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
829         }
830     }
831 }
832
833 struct ZlibDecodeMultiple<R>
834 where
835     R: Read + Seek,
836 {
837     reader: Option<ZlibDecoder<R>>,
838 }
839
840 impl<R> ZlibDecodeMultiple<R>
841 where
842     R: Read + Seek,
843 {
844     fn new(reader: R) -> ZlibDecodeMultiple<R> {
845         ZlibDecodeMultiple {
846             reader: Some(ZlibDecoder::new(reader)),
847         }
848     }
849 }
850
851 impl<R> Read for ZlibDecodeMultiple<R>
852 where
853     R: Read + Seek,
854 {
855     fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
856         loop {
857             match self.reader.as_mut().unwrap().read(buf)? {
858                 0 => {
859                     let inner = self.reader.take().unwrap().into_inner();
860                     self.reader = Some(ZlibDecoder::new(inner));
861                 }
862                 n => return Ok(n),
863             };
864         }
865     }
866 }
867
868 impl<R> Seek for ZlibDecodeMultiple<R>
869 where
870     R: Read + Seek,
871 {
872     fn seek(&mut self, pos: SeekFrom) -> Result<u64, IoError> {
873         self.reader.as_mut().unwrap().get_mut().seek(pos)
874     }
875 }
876
877 enum ReaderState {
878     Start,
879     Headers,
880     ZlibHeader,
881     ZlibTrailer {
882         ztrailer_offset: u64,
883         ztrailer_len: u64,
884     },
885     Cases,
886     End,
887 }
888
889 pub struct Reader<R>
890 where
891     R: Read + Seek + 'static,
892 {
893     reader: Option<R>,
894     warn: Box<dyn Fn(Warning)>,
895
896     header: HeaderRecord<RawString>,
897     var_types: Vec<VarType>,
898
899     state: ReaderState,
900 }
901
902 impl<R> Reader<R>
903 where
904     R: Read + Seek + 'static,
905 {
906     pub fn new<F>(mut reader: R, warn: F) -> Result<Self, Error>
907     where
908         F: Fn(Warning) + 'static,
909     {
910         let header = HeaderRecord::read(&mut reader)?;
911         Ok(Self {
912             reader: Some(reader),
913             warn: Box::new(warn),
914             header,
915             var_types: Vec::new(),
916             state: ReaderState::Start,
917         })
918     }
919     fn cases(&mut self) -> Cases {
920         self.state = ReaderState::End;
921         Cases::new(
922             self.reader.take().unwrap(),
923             take(&mut self.var_types),
924             &self.header,
925         )
926     }
927     fn _next(&mut self) -> Option<<Self as Iterator>::Item> {
928         match self.state {
929             ReaderState::Start => {
930                 self.state = ReaderState::Headers;
931                 Some(Ok(Record::Header(self.header.clone())))
932             }
933             ReaderState::Headers => {
934                 let record = loop {
935                     match Record::read(
936                         self.reader.as_mut().unwrap(),
937                         self.header.endian,
938                         self.var_types.as_slice(),
939                         &self.warn,
940                     ) {
941                         Ok(Some(record)) => break record,
942                         Ok(None) => (),
943                         Err(error) => return Some(Err(error)),
944                     }
945                 };
946                 match record {
947                     Record::Variable(VariableRecord { width, .. }) => {
948                         self.var_types.push(if width == 0 {
949                             VarType::Numeric
950                         } else {
951                             VarType::String
952                         });
953                     }
954                     Record::EndOfHeaders(_) => {
955                         self.state = if let Some(Compression::ZLib) = self.header.compression {
956                             ReaderState::ZlibHeader
957                         } else {
958                             ReaderState::Cases
959                         };
960                     }
961                     _ => (),
962                 };
963                 Some(Ok(record))
964             }
965             ReaderState::ZlibHeader => {
966                 let zheader = match ZHeader::read(self.reader.as_mut().unwrap(), self.header.endian)
967                 {
968                     Ok(zheader) => zheader,
969                     Err(error) => return Some(Err(error)),
970                 };
971                 self.state = ReaderState::ZlibTrailer {
972                     ztrailer_offset: zheader.ztrailer_offset,
973                     ztrailer_len: zheader.ztrailer_len,
974                 };
975                 Some(Ok(Record::ZHeader(zheader)))
976             }
977             ReaderState::ZlibTrailer {
978                 ztrailer_offset,
979                 ztrailer_len,
980             } => {
981                 match ZTrailer::read(
982                     self.reader.as_mut().unwrap(),
983                     self.header.endian,
984                     ztrailer_offset,
985                     ztrailer_len,
986                 ) {
987                     Ok(None) => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
988                     Ok(Some(ztrailer)) => Some(Ok(Record::ZTrailer(ztrailer))),
989                     Err(error) => Some(Err(error)),
990                 }
991             }
992             ReaderState::Cases => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
993             ReaderState::End => None,
994         }
995     }
996 }
997
998 impl<R> Iterator for Reader<R>
999 where
1000     R: Read + Seek + 'static,
1001 {
1002     type Item = Result<Record, Error>;
1003
1004     fn next(&mut self) -> Option<Self::Item> {
1005         let retval = self._next();
1006         if matches!(retval, Some(Err(_))) {
1007             self.state = ReaderState::End;
1008         }
1009         retval
1010     }
1011 }
1012
1013 trait ReadSeek: Read + Seek {}
1014 impl<T> ReadSeek for T where T: Read + Seek {}
1015
1016 pub struct Cases {
1017     reader: Box<dyn ReadSeek>,
1018     var_types: Vec<VarType>,
1019     compression: Option<Compression>,
1020     bias: f64,
1021     endian: Endian,
1022     codes: VecDeque<u8>,
1023     eof: bool,
1024 }
1025
1026 impl Debug for Cases {
1027     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1028         write!(f, "Cases")
1029     }
1030 }
1031
1032 impl Cases {
1033     fn new<R>(reader: R, var_types: Vec<VarType>, header: &HeaderRecord<RawString>) -> Self
1034     where
1035         R: Read + Seek + 'static,
1036     {
1037         Self {
1038             reader: if header.compression == Some(Compression::ZLib) {
1039                 Box::new(ZlibDecodeMultiple::new(reader))
1040             } else {
1041                 Box::new(reader)
1042             },
1043             var_types,
1044             compression: header.compression,
1045             bias: header.bias,
1046             endian: header.endian,
1047             codes: VecDeque::with_capacity(8),
1048             eof: false,
1049         }
1050     }
1051 }
1052
1053 impl Iterator for Cases {
1054     type Item = Result<Vec<RawValue>, Error>;
1055
1056     fn next(&mut self) -> Option<Self::Item> {
1057         if self.eof {
1058             return None;
1059         }
1060
1061         let retval = if self.compression.is_some() {
1062             Value::read_compressed_case(
1063                 &mut self.reader,
1064                 &self.var_types,
1065                 &mut self.codes,
1066                 self.endian,
1067                 self.bias,
1068             )
1069             .transpose()
1070         } else {
1071             Value::read_case(&mut self.reader, &self.var_types, self.endian).transpose()
1072         };
1073         self.eof = matches!(retval, None | Some(Err(_)));
1074         retval
1075     }
1076 }
1077
1078 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
1079 pub struct Spec(pub u32);
1080
1081 impl Debug for Spec {
1082     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1083         let type_ = format_name(self.0 >> 16);
1084         let w = (self.0 >> 8) & 0xff;
1085         let d = self.0 & 0xff;
1086         write!(f, "{:06x} ({type_}{w}.{d})", self.0)
1087     }
1088 }
1089
1090 fn format_name(type_: u32) -> Cow<'static, str> {
1091     match type_ {
1092         1 => "A",
1093         2 => "AHEX",
1094         3 => "COMMA",
1095         4 => "DOLLAR",
1096         5 => "F",
1097         6 => "IB",
1098         7 => "PIBHEX",
1099         8 => "P",
1100         9 => "PIB",
1101         10 => "PK",
1102         11 => "RB",
1103         12 => "RBHEX",
1104         15 => "Z",
1105         16 => "N",
1106         17 => "E",
1107         20 => "DATE",
1108         21 => "TIME",
1109         22 => "DATETIME",
1110         23 => "ADATE",
1111         24 => "JDATE",
1112         25 => "DTIME",
1113         26 => "WKDAY",
1114         27 => "MONTH",
1115         28 => "MOYR",
1116         29 => "QYR",
1117         30 => "WKYR",
1118         31 => "PCT",
1119         32 => "DOT",
1120         33 => "CCA",
1121         34 => "CCB",
1122         35 => "CCC",
1123         36 => "CCD",
1124         37 => "CCE",
1125         38 => "EDATE",
1126         39 => "SDATE",
1127         40 => "MTIME",
1128         41 => "YMDHMS",
1129         _ => return format!("<unknown format {type_}>").into(),
1130     }
1131     .into()
1132 }
1133
1134 #[derive(Clone)]
1135 pub struct MissingValues<S = String>
1136 where
1137     S: Debug,
1138 {
1139     /// Individual missing values, up to 3 of them.
1140     pub values: Vec<Value<S>>,
1141
1142     /// Optional range of missing values.
1143     pub range: Option<(Value<S>, Value<S>)>,
1144 }
1145
1146 impl<S> Debug for MissingValues<S>
1147 where
1148     S: Debug,
1149 {
1150     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1151         for (i, value) in self.values.iter().enumerate() {
1152             if i > 0 {
1153                 write!(f, ", ")?;
1154             }
1155             write!(f, "{value:?}")?;
1156         }
1157
1158         if let Some((low, high)) = &self.range {
1159             if !self.values.is_empty() {
1160                 write!(f, ", ")?;
1161             }
1162             write!(f, "{low:?} THRU {high:?}")?;
1163         }
1164
1165         if self.is_empty() {
1166             write!(f, "none")?;
1167         }
1168
1169         Ok(())
1170     }
1171 }
1172
1173 impl<S> MissingValues<S>
1174 where
1175     S: Debug,
1176 {
1177     fn is_empty(&self) -> bool {
1178         self.values.is_empty() && self.range.is_none()
1179     }
1180 }
1181
1182 impl<S> Default for MissingValues<S>
1183 where
1184     S: Debug,
1185 {
1186     fn default() -> Self {
1187         Self {
1188             values: Vec::new(),
1189             range: None,
1190         }
1191     }
1192 }
1193
1194 impl MissingValues<RawStr<8>> {
1195     fn read<R: Read + Seek>(
1196         r: &mut R,
1197         offset: u64,
1198         width: i32,
1199         code: i32,
1200         endian: Endian,
1201     ) -> Result<Self, Error> {
1202         let (n_values, has_range) = match (width, code) {
1203             (_, 0..=3) => (code, false),
1204             (0, -2) => (0, true),
1205             (0, -3) => (1, true),
1206             (0, _) => return Err(Error::BadNumericMissingValueCode { offset, code }),
1207             (_, _) => return Err(Error::BadStringMissingValueCode { offset, code }),
1208         };
1209
1210         let var_type = if width == 0 {
1211             VarType::Numeric
1212         } else {
1213             VarType::String
1214         };
1215
1216         let mut values = Vec::new();
1217         for _ in 0..n_values {
1218             values.push(RawValue::read(r, var_type, endian)?);
1219         }
1220         let range = if has_range {
1221             let low = RawValue::read(r, var_type, endian)?;
1222             let high = RawValue::read(r, var_type, endian)?;
1223             Some((low, high))
1224         } else {
1225             None
1226         };
1227         Ok(Self { values, range })
1228     }
1229     fn decode(&self, decoder: &Decoder) -> MissingValues<String> {
1230         MissingValues {
1231             values: self
1232                 .values
1233                 .iter()
1234                 .map(|value| value.decode(decoder))
1235                 .collect(),
1236             range: self
1237                 .range
1238                 .as_ref()
1239                 .map(|(low, high)| (low.decode(decoder), high.decode(decoder))),
1240         }
1241     }
1242 }
1243
1244 #[derive(Clone)]
1245 pub struct VariableRecord<S, V>
1246 where
1247     S: Debug,
1248     V: Debug,
1249 {
1250     /// Range of offsets in file.
1251     pub offsets: Range<u64>,
1252
1253     /// Variable width, in the range -1..=255.
1254     pub width: i32,
1255
1256     /// Variable name, padded on the right with spaces.
1257     pub name: S,
1258
1259     /// Print format.
1260     pub print_format: Spec,
1261
1262     /// Write format.
1263     pub write_format: Spec,
1264
1265     /// Missing values.
1266     pub missing_values: MissingValues<V>,
1267
1268     /// Optional variable label.
1269     pub label: Option<S>,
1270 }
1271
1272 impl<S, V> Debug for VariableRecord<S, V>
1273 where
1274     S: Debug,
1275     V: Debug,
1276 {
1277     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1278         writeln!(
1279             f,
1280             "Width: {} ({})",
1281             self.width,
1282             match self.width.cmp(&0) {
1283                 Ordering::Greater => "string",
1284                 Ordering::Equal => "numeric",
1285                 Ordering::Less => "long string continuation record",
1286             }
1287         )?;
1288         writeln!(f, "Print format: {:?}", self.print_format)?;
1289         writeln!(f, "Write format: {:?}", self.write_format)?;
1290         writeln!(f, "Name: {:?}", &self.name)?;
1291         writeln!(f, "Variable label: {:?}", self.label)?;
1292         writeln!(f, "Missing values: {:?}", self.missing_values)
1293     }
1294 }
1295
1296 impl VariableRecord<RawString, RawStr<8>> {
1297     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1298         let start_offset = r.stream_position()?;
1299         let width: i32 = endian.parse(read_bytes(r)?);
1300         let code_offset = r.stream_position()?;
1301         let has_variable_label: u32 = endian.parse(read_bytes(r)?);
1302         let missing_value_code: i32 = endian.parse(read_bytes(r)?);
1303         let print_format = Spec(endian.parse(read_bytes(r)?));
1304         let write_format = Spec(endian.parse(read_bytes(r)?));
1305         let name = RawString(read_vec(r, 8)?);
1306
1307         let label = match has_variable_label {
1308             0 => None,
1309             1 => {
1310                 let len: u32 = endian.parse(read_bytes(r)?);
1311                 let read_len = len.min(65535) as usize;
1312                 let label = RawString(read_vec(r, read_len)?);
1313
1314                 let padding_bytes = Integer::next_multiple_of(&len, &4) - len;
1315                 let _ = read_vec(r, padding_bytes as usize)?;
1316
1317                 Some(label)
1318             }
1319             _ => {
1320                 return Err(Error::BadVariableLabelCode {
1321                     start_offset,
1322                     code_offset,
1323                     code: has_variable_label,
1324                 })
1325             }
1326         };
1327
1328         let missing_values =
1329             MissingValues::read(r, start_offset, width, missing_value_code, endian)?;
1330
1331         let end_offset = r.stream_position()?;
1332
1333         Ok(Record::Variable(VariableRecord {
1334             offsets: start_offset..end_offset,
1335             width,
1336             name,
1337             print_format,
1338             write_format,
1339             missing_values,
1340             label,
1341         }))
1342     }
1343
1344     pub fn decode(&self, decoder: &Decoder) -> DecodedRecord {
1345         DecodedRecord::Variable(VariableRecord {
1346             offsets: self.offsets.clone(),
1347             width: self.width,
1348             name: decoder.decode(&self.name),
1349             print_format: self.print_format,
1350             write_format: self.write_format,
1351             missing_values: self.missing_values.decode(decoder),
1352             label: self.label.as_ref().map(|label| decoder.decode(label)),
1353         })
1354     }
1355 }
1356
1357 #[derive(Copy, Clone)]
1358 pub struct UntypedValue(pub [u8; 8]);
1359
1360 impl Debug for UntypedValue {
1361     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1362         let little: f64 = Endian::Little.parse(self.0);
1363         let little = format!("{:?}", little);
1364         let big: f64 = Endian::Big.parse(self.0);
1365         let big = format!("{:?}", big);
1366         let number = if little.len() <= big.len() {
1367             little
1368         } else {
1369             big
1370         };
1371         write!(f, "{number}")?;
1372
1373         let string = default_decode(&self.0);
1374         let string = string
1375             .split(|c: char| c == '\0' || c.is_control())
1376             .next()
1377             .unwrap();
1378         write!(f, "{string:?}")?;
1379         Ok(())
1380     }
1381 }
1382
1383 #[derive(Clone)]
1384 pub struct RawString(pub Vec<u8>);
1385
1386 impl From<Vec<u8>> for RawString {
1387     fn from(source: Vec<u8>) -> Self {
1388         Self(source)
1389     }
1390 }
1391
1392 impl From<&[u8]> for RawString {
1393     fn from(source: &[u8]) -> Self {
1394         Self(source.into())
1395     }
1396 }
1397
1398 impl Debug for RawString {
1399     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1400         write!(f, "{:?}", default_decode(self.0.as_slice()))
1401     }
1402 }
1403
1404 #[derive(Copy, Clone)]
1405 pub struct RawStr<const N: usize>(pub [u8; N]);
1406
1407 impl<const N: usize> From<[u8; N]> for RawStr<N> {
1408     fn from(source: [u8; N]) -> Self {
1409         Self(source)
1410     }
1411 }
1412
1413 impl<const N: usize> Debug for RawStr<N> {
1414     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1415         write!(f, "{:?}", default_decode(&self.0))
1416     }
1417 }
1418
1419 #[derive(Clone, Debug)]
1420 pub struct ValueLabel<V, S>
1421 where
1422     V: Debug,
1423     S: Debug,
1424 {
1425     pub value: Value<V>,
1426     pub label: S,
1427 }
1428
1429 #[derive(Clone)]
1430 pub struct ValueLabelRecord<V, S>
1431 where
1432     V: Debug,
1433     S: Debug,
1434 {
1435     /// Range of offsets in file.
1436     pub offsets: Range<u64>,
1437
1438     /// The labels.
1439     pub labels: Vec<ValueLabel<V, S>>,
1440
1441     /// The 1-based indexes of the variable indexes.
1442     pub dict_indexes: Vec<u32>,
1443
1444     /// The types of the variables.
1445     pub var_type: VarType,
1446 }
1447
1448 impl<V, S> Debug for ValueLabelRecord<V, S>
1449 where
1450     V: Debug,
1451     S: Debug,
1452 {
1453     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1454         writeln!(f, "labels: ")?;
1455         for label in self.labels.iter() {
1456             writeln!(f, "{label:?}")?;
1457         }
1458         write!(f, "apply to {} variables", self.var_type)?;
1459         for dict_index in self.dict_indexes.iter() {
1460             write!(f, " #{dict_index}")?;
1461         }
1462         Ok(())
1463     }
1464 }
1465
1466 impl<V, S> Header for ValueLabelRecord<V, S>
1467 where
1468     V: Debug,
1469     S: Debug,
1470 {
1471     fn offsets(&self) -> Range<u64> {
1472         self.offsets.clone()
1473     }
1474 }
1475
1476 impl<V, S> ValueLabelRecord<V, S>
1477 where
1478     V: Debug,
1479     S: Debug,
1480 {
1481     /// Maximum number of value labels in a record.
1482     pub const MAX_LABELS: u32 = u32::MAX / 8;
1483
1484     /// Maximum number of variable indexes in a record.
1485     pub const MAX_INDEXES: u32 = u32::MAX / 8;
1486 }
1487
1488 impl ValueLabelRecord<RawStr<8>, RawString> {
1489     fn read<R: Read + Seek>(
1490         r: &mut R,
1491         endian: Endian,
1492         var_types: &[VarType],
1493         warn: &dyn Fn(Warning),
1494     ) -> Result<Option<Record>, Error> {
1495         let label_offset = r.stream_position()?;
1496         let n: u32 = endian.parse(read_bytes(r)?);
1497         if n > Self::MAX_LABELS {
1498             return Err(Error::BadNumberOfValueLabels {
1499                 offset: label_offset,
1500                 n,
1501                 max: Self::MAX_LABELS,
1502             });
1503         }
1504
1505         let mut labels = Vec::new();
1506         for _ in 0..n {
1507             let value = UntypedValue(read_bytes(r)?);
1508             let label_len: u8 = endian.parse(read_bytes(r)?);
1509             let label_len = label_len as usize;
1510             let padded_len = Integer::next_multiple_of(&(label_len + 1), &8);
1511
1512             let mut label = read_vec(r, padded_len - 1)?;
1513             label.truncate(label_len);
1514             labels.push((value, RawString(label)));
1515         }
1516
1517         let index_offset = r.stream_position()?;
1518         let rec_type: u32 = endian.parse(read_bytes(r)?);
1519         if rec_type != 4 {
1520             return Err(Error::ExpectedVarIndexRecord {
1521                 offset: index_offset,
1522                 rec_type,
1523             });
1524         }
1525
1526         let n: u32 = endian.parse(read_bytes(r)?);
1527         if n > Self::MAX_INDEXES {
1528             return Err(Error::TooManyVarIndexes {
1529                 offset: index_offset,
1530                 n,
1531                 max: Self::MAX_INDEXES,
1532             });
1533         }
1534
1535         let index_offset = r.stream_position()?;
1536         let mut dict_indexes = Vec::with_capacity(n as usize);
1537         let mut invalid_indexes = Vec::new();
1538         for _ in 0..n {
1539             let index: u32 = endian.parse(read_bytes(r)?);
1540             if index == 0 || index as usize > var_types.len() {
1541                 dict_indexes.push(index);
1542             } else {
1543                 invalid_indexes.push(index);
1544             }
1545         }
1546         if !invalid_indexes.is_empty() {
1547             warn(Warning::InvalidVarIndexes {
1548                 offset: index_offset,
1549                 max: var_types.len(),
1550                 invalid: invalid_indexes,
1551             });
1552         }
1553
1554         let Some(&first_index) = dict_indexes.first() else {
1555             warn(Warning::NoVarIndexes {
1556                 offset: index_offset,
1557             });
1558             return Ok(None);
1559         };
1560         let var_type = var_types[first_index as usize - 1];
1561         let mut wrong_type_indexes = Vec::new();
1562         dict_indexes.retain(|&index| {
1563             if var_types[index as usize - 1] != var_type {
1564                 wrong_type_indexes.push(index);
1565                 false
1566             } else {
1567                 true
1568             }
1569         });
1570         if !wrong_type_indexes.is_empty() {
1571             warn(Warning::MixedVarTypes {
1572                 offset: index_offset,
1573                 var_type,
1574                 wrong_types: wrong_type_indexes,
1575             });
1576         }
1577
1578         let labels = labels
1579             .into_iter()
1580             .map(|(value, label)| ValueLabel {
1581                 value: Value::from_raw(&value, var_type, endian),
1582                 label,
1583             })
1584             .collect();
1585
1586         let end_offset = r.stream_position()?;
1587         Ok(Some(Record::ValueLabel(ValueLabelRecord {
1588             offsets: label_offset..end_offset,
1589             labels,
1590             dict_indexes,
1591             var_type,
1592         })))
1593     }
1594
1595     fn decode<'a>(&'a self, decoder: &Decoder) -> ValueLabelRecord<RawStr<8>, Cow<'a, str>> {
1596         let labels = self
1597             .labels
1598             .iter()
1599             .map(|ValueLabel { value, label }| ValueLabel {
1600                 value: *value,
1601                 label: decoder.decode(label),
1602             })
1603             .collect();
1604         ValueLabelRecord {
1605             offsets: self.offsets.clone(),
1606             labels,
1607             dict_indexes: self.dict_indexes.clone(),
1608             var_type: self.var_type,
1609         }
1610     }
1611 }
1612
1613 #[derive(Clone, Debug)]
1614 pub struct DocumentRecord<S>
1615 where
1616     S: Debug,
1617 {
1618     pub offsets: Range<u64>,
1619
1620     /// The document, as an array of 80-byte lines.
1621     pub lines: Vec<S>,
1622 }
1623
1624 pub type RawDocumentLine = RawStr<DOC_LINE_LEN>;
1625
1626 /// Length of a line in a document.  Document lines are fixed-length and
1627 /// padded on the right with spaces.
1628 pub const DOC_LINE_LEN: usize = 80;
1629
1630 impl DocumentRecord<RawDocumentLine> {
1631     /// Maximum number of lines we will accept in a document.  This is simply
1632     /// the maximum number that will fit in a 32-bit space.
1633     pub const MAX_LINES: usize = i32::MAX as usize / DOC_LINE_LEN;
1634
1635     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1636         let start_offset = r.stream_position()?;
1637         let n: u32 = endian.parse(read_bytes(r)?);
1638         let n = n as usize;
1639         if n > Self::MAX_LINES {
1640             Err(Error::BadDocumentLength {
1641                 offset: start_offset,
1642                 n,
1643                 max: Self::MAX_LINES,
1644             })
1645         } else {
1646             let mut lines = Vec::with_capacity(n);
1647             for _ in 0..n {
1648                 lines.push(RawStr(read_bytes(r)?));
1649             }
1650             let end_offset = r.stream_position()?;
1651             Ok(Record::Document(DocumentRecord {
1652                 offsets: start_offset..end_offset,
1653                 lines,
1654             }))
1655         }
1656     }
1657
1658     pub fn decode(&self, decoder: &Decoder) -> DecodedRecord {
1659         DecodedRecord::Document(DocumentRecord {
1660             offsets: self.offsets.clone(),
1661             lines: self
1662                 .lines
1663                 .iter()
1664                 .map(|s| decoder.decode_slice(&s.0))
1665                 .collect(),
1666         })
1667     }
1668 }
1669
1670 impl<S> Header for DocumentRecord<S>
1671 where
1672     S: Debug,
1673 {
1674     fn offsets(&self) -> Range<u64> {
1675         self.offsets.clone()
1676     }
1677 }
1678
1679 trait ExtensionRecord {
1680     const SUBTYPE: u32;
1681     const SIZE: Option<u32>;
1682     const COUNT: Option<u32>;
1683     const NAME: &'static str;
1684     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning>;
1685 }
1686
1687 #[derive(Clone, Debug)]
1688 pub struct IntegerInfoRecord {
1689     pub offsets: Range<u64>,
1690     pub version: (i32, i32, i32),
1691     pub machine_code: i32,
1692     pub floating_point_rep: i32,
1693     pub compression_code: i32,
1694     pub endianness: i32,
1695     pub character_code: i32,
1696 }
1697
1698 impl ExtensionRecord for IntegerInfoRecord {
1699     const SUBTYPE: u32 = 3;
1700     const SIZE: Option<u32> = Some(4);
1701     const COUNT: Option<u32> = Some(8);
1702     const NAME: &'static str = "integer record";
1703
1704     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
1705         ext.check_size::<Self>()?;
1706
1707         let mut input = &ext.data[..];
1708         let data: Vec<i32> = (0..8)
1709             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1710             .collect();
1711         Ok(Record::IntegerInfo(IntegerInfoRecord {
1712             offsets: ext.offsets.clone(),
1713             version: (data[0], data[1], data[2]),
1714             machine_code: data[3],
1715             floating_point_rep: data[4],
1716             compression_code: data[5],
1717             endianness: data[6],
1718             character_code: data[7],
1719         }))
1720     }
1721 }
1722
1723 #[derive(Clone, Debug)]
1724 pub struct FloatInfoRecord {
1725     pub sysmis: f64,
1726     pub highest: f64,
1727     pub lowest: f64,
1728 }
1729
1730 impl ExtensionRecord for FloatInfoRecord {
1731     const SUBTYPE: u32 = 4;
1732     const SIZE: Option<u32> = Some(8);
1733     const COUNT: Option<u32> = Some(3);
1734     const NAME: &'static str = "floating point record";
1735
1736     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
1737         ext.check_size::<Self>()?;
1738
1739         let mut input = &ext.data[..];
1740         let data: Vec<f64> = (0..3)
1741             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1742             .collect();
1743         Ok(Record::FloatInfo(FloatInfoRecord {
1744             sysmis: data[0],
1745             highest: data[1],
1746             lowest: data[2],
1747         }))
1748     }
1749 }
1750
1751 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1752 pub enum CategoryLabels {
1753     VarLabels,
1754     CountedValues,
1755 }
1756
1757 #[derive(Clone, Debug)]
1758 pub enum MultipleResponseType {
1759     MultipleDichotomy {
1760         value: RawString,
1761         labels: CategoryLabels,
1762     },
1763     MultipleCategory,
1764 }
1765
1766 impl MultipleResponseType {
1767     fn parse(input: &[u8]) -> Result<(MultipleResponseType, &[u8]), Warning> {
1768         let (mr_type, input) = match input.split_first() {
1769             Some((b'C', input)) => (MultipleResponseType::MultipleCategory, input),
1770             Some((b'D', input)) => {
1771                 let (value, input) = parse_counted_string(input)?;
1772                 (
1773                     MultipleResponseType::MultipleDichotomy {
1774                         value,
1775                         labels: CategoryLabels::VarLabels,
1776                     },
1777                     input,
1778                 )
1779             }
1780             Some((b'E', input)) => {
1781                 let (labels, input) = if let Some(rest) = input.strip_prefix(b" 1 ") {
1782                     (CategoryLabels::CountedValues, rest)
1783                 } else if let Some(rest) = input.strip_prefix(b" 11 ") {
1784                     (CategoryLabels::VarLabels, rest)
1785                 } else {
1786                     return Err(Warning::TBD);
1787                 };
1788                 let (value, input) = parse_counted_string(input)?;
1789                 (
1790                     MultipleResponseType::MultipleDichotomy { value, labels },
1791                     input,
1792                 )
1793             }
1794             _ => return Err(Warning::TBD),
1795         };
1796         Ok((mr_type, input))
1797     }
1798 }
1799
1800 #[derive(Clone, Debug)]
1801 pub struct MultipleResponseSet<I, S>
1802 where
1803     I: Debug,
1804     S: Debug,
1805 {
1806     pub name: I,
1807     pub label: S,
1808     pub mr_type: MultipleResponseType,
1809     pub short_names: Vec<I>,
1810 }
1811
1812 impl MultipleResponseSet<RawString, RawString> {
1813     fn parse(input: &[u8]) -> Result<(Self, &[u8]), Warning> {
1814         let Some(equals) = input.iter().position(|&b| b == b'=') else {
1815             return Err(Warning::TBD);
1816         };
1817         let (name, input) = input.split_at(equals);
1818         let (mr_type, input) = MultipleResponseType::parse(input)?;
1819         let Some(input) = input.strip_prefix(b" ") else {
1820             return Err(Warning::TBD);
1821         };
1822         let (label, mut input) = parse_counted_string(input)?;
1823         let mut vars = Vec::new();
1824         while input.first() != Some(&b'\n') {
1825             match input.split_first() {
1826                 Some((b' ', rest)) => {
1827                     let Some(length) = rest.iter().position(|b| b" \n".contains(b)) else {
1828                         return Err(Warning::TBD);
1829                     };
1830                     let (var, rest) = rest.split_at(length);
1831                     if !var.is_empty() {
1832                         vars.push(var.into());
1833                     }
1834                     input = rest;
1835                 }
1836                 _ => return Err(Warning::TBD),
1837             }
1838         }
1839         while input.first() == Some(&b'\n') {
1840             input = &input[1..];
1841         }
1842         Ok((
1843             MultipleResponseSet {
1844                 name: name.into(),
1845                 label,
1846                 mr_type,
1847                 short_names: vars,
1848             },
1849             input,
1850         ))
1851     }
1852
1853     fn decode<'a>(
1854         &'a self,
1855         decoder: &Decoder,
1856     ) -> Result<MultipleResponseSet<Identifier, Cow<'a, str>>, Warning> {
1857         let mut short_names = Vec::with_capacity(self.short_names.len());
1858         for short_name in self.short_names.iter() {
1859             if let Some(short_name) = decoder
1860                 .decode_identifier(short_name)
1861                 .map_err(Warning::InvalidMrSetName)
1862                 .issue_warning(&decoder.warn)
1863             {
1864                 short_names.push(short_name);
1865             }
1866         }
1867         Ok(MultipleResponseSet {
1868             name: decoder
1869                 .decode_identifier(&self.name)
1870                 .map_err(Warning::InvalidMrSetVariableName)?,
1871             label: decoder.decode(&self.label),
1872             mr_type: self.mr_type.clone(),
1873             short_names,
1874         })
1875     }
1876 }
1877
1878 #[derive(Clone, Debug)]
1879 pub struct MultipleResponseRecord<I, S>(pub Vec<MultipleResponseSet<I, S>>)
1880 where
1881     I: Debug,
1882     S: Debug;
1883
1884 impl ExtensionRecord for MultipleResponseRecord<RawString, RawString> {
1885     const SUBTYPE: u32 = 7;
1886     const SIZE: Option<u32> = Some(1);
1887     const COUNT: Option<u32> = None;
1888     const NAME: &'static str = "multiple response set record";
1889
1890     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Warning> {
1891         ext.check_size::<Self>()?;
1892
1893         let mut input = &ext.data[..];
1894         let mut sets = Vec::new();
1895         while !input.is_empty() {
1896             let (set, rest) = MultipleResponseSet::parse(input)?;
1897             sets.push(set);
1898             input = rest;
1899         }
1900         Ok(Record::MultipleResponse(MultipleResponseRecord(sets)))
1901     }
1902 }
1903
1904 impl MultipleResponseRecord<RawString, RawString> {
1905     fn decode(&self, decoder: &Decoder) -> DecodedRecord {
1906         let mut sets = Vec::new();
1907         for set in self.0.iter() {
1908             if let Some(set) = set.decode(decoder).issue_warning(&decoder.warn) {
1909                 sets.push(set);
1910             }
1911         }
1912         DecodedRecord::MultipleResponse(MultipleResponseRecord(sets))
1913     }
1914 }
1915
1916 fn parse_counted_string(input: &[u8]) -> Result<(RawString, &[u8]), Warning> {
1917     let Some(space) = input.iter().position(|&b| b == b' ') else {
1918         return Err(Warning::TBD);
1919     };
1920     let Ok(length) = from_utf8(&input[..space]) else {
1921         return Err(Warning::TBD);
1922     };
1923     let Ok(length): Result<usize, _> = length.parse() else {
1924         return Err(Warning::TBD);
1925     };
1926
1927     let input = &input[space + 1..];
1928     if input.len() < length {
1929         return Err(Warning::TBD);
1930     };
1931
1932     let (string, rest) = input.split_at(length);
1933     Ok((string.into(), rest))
1934 }
1935
1936 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1937 pub enum Measure {
1938     Nominal,
1939     Ordinal,
1940     Scale,
1941 }
1942
1943 impl Measure {
1944     pub fn default_for_type(var_type: VarType) -> Option<Measure> {
1945         match var_type {
1946             VarType::Numeric => None,
1947             VarType::String => Some(Self::Nominal),
1948         }
1949     }
1950
1951     fn try_decode(source: u32) -> Result<Option<Measure>, Warning> {
1952         match source {
1953             0 => Ok(None),
1954             1 => Ok(Some(Measure::Nominal)),
1955             2 => Ok(Some(Measure::Ordinal)),
1956             3 => Ok(Some(Measure::Scale)),
1957             _ => Err(Warning::InvalidMeasurement(source)),
1958         }
1959     }
1960 }
1961
1962 #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1963 pub enum Alignment {
1964     Left,
1965     Right,
1966     Center,
1967 }
1968
1969 impl Alignment {
1970     fn try_decode(source: u32) -> Result<Option<Alignment>, Warning> {
1971         match source {
1972             0 => Ok(None),
1973             1 => Ok(Some(Alignment::Left)),
1974             2 => Ok(Some(Alignment::Right)),
1975             3 => Ok(Some(Alignment::Center)),
1976             _ => Err(Warning::InvalidAlignment(source)),
1977         }
1978     }
1979
1980     pub fn default_for_type(var_type: VarType) -> Self {
1981         match var_type {
1982             VarType::Numeric => Self::Right,
1983             VarType::String => Self::Left,
1984         }
1985     }
1986 }
1987
1988 #[derive(Clone, Debug)]
1989 pub struct VarDisplay {
1990     pub measure: Option<Measure>,
1991     pub width: Option<u32>,
1992     pub alignment: Option<Alignment>,
1993 }
1994
1995 #[derive(Clone, Debug)]
1996 pub struct VarDisplayRecord(pub Vec<VarDisplay>);
1997
1998 impl VarDisplayRecord {
1999     const SUBTYPE: u32 = 11;
2000
2001     fn parse(
2002         ext: &Extension,
2003         n_vars: usize,
2004         endian: Endian,
2005         warn: &dyn Fn(Warning),
2006     ) -> Result<Record, Warning> {
2007         if ext.size != 4 {
2008             return Err(Warning::BadRecordSize {
2009                 offset: ext.offsets.start,
2010                 record: String::from("variable display record"),
2011                 size: ext.size,
2012                 expected_size: 4,
2013             });
2014         }
2015
2016         let has_width = if ext.count as usize == 3 * n_vars {
2017             true
2018         } else if ext.count as usize == 2 * n_vars {
2019             false
2020         } else {
2021             return Err(Warning::TBD);
2022         };
2023
2024         let mut var_displays = Vec::new();
2025         let mut input = &ext.data[..];
2026         for _ in 0..n_vars {
2027             let measure = Measure::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
2028                 .issue_warning(&warn)
2029                 .flatten();
2030             let width = has_width.then(|| endian.parse(read_bytes(&mut input).unwrap()));
2031             let alignment = Alignment::try_decode(endian.parse(read_bytes(&mut input).unwrap()))
2032                 .issue_warning(&warn)
2033                 .flatten();
2034             var_displays.push(VarDisplay {
2035                 measure,
2036                 width,
2037                 alignment,
2038             });
2039         }
2040         Ok(Record::VarDisplay(VarDisplayRecord(var_displays)))
2041     }
2042 }
2043
2044 #[derive(Clone, Debug)]
2045 pub struct LongStringMissingValues<N, V>
2046 where
2047     N: Debug,
2048     V: Debug,
2049 {
2050     /// Variable name.
2051     pub var_name: N,
2052
2053     /// Missing values.
2054     pub missing_values: MissingValues<V>,
2055 }
2056
2057 impl LongStringMissingValues<RawString, RawStr<8>> {
2058     fn decode(
2059         &self,
2060         decoder: &Decoder,
2061     ) -> Result<LongStringMissingValues<Identifier, String>, IdError> {
2062         Ok(LongStringMissingValues {
2063             var_name: decoder.decode_identifier(&self.var_name)?,
2064             missing_values: self.missing_values.decode(decoder),
2065         })
2066     }
2067 }
2068
2069 #[derive(Clone, Debug)]
2070 pub struct LongStringMissingValueRecord<N, V>(pub Vec<LongStringMissingValues<N, V>>)
2071 where
2072     N: Debug,
2073     V: Debug;
2074
2075 impl ExtensionRecord for LongStringMissingValueRecord<RawString, RawStr<8>> {
2076     const SUBTYPE: u32 = 22;
2077     const SIZE: Option<u32> = Some(1);
2078     const COUNT: Option<u32> = None;
2079     const NAME: &'static str = "long string missing values record";
2080
2081     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
2082         ext.check_size::<Self>()?;
2083
2084         let mut input = &ext.data[..];
2085         let mut missing_value_set = Vec::new();
2086         while !input.is_empty() {
2087             let var_name = read_string(&mut input, endian)?;
2088             let n_missing_values: u8 = endian.parse(read_bytes(&mut input)?);
2089             let value_len: u32 = endian.parse(read_bytes(&mut input)?);
2090             if value_len != 8 {
2091                 let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offsets.start;
2092                 return Err(Warning::BadLongMissingValueLength {
2093                     record_offset: ext.offsets.start,
2094                     offset,
2095                     value_len,
2096                 });
2097             }
2098             let mut values = Vec::new();
2099             for i in 0..n_missing_values {
2100                 let value: [u8; 8] = read_bytes(&mut input)?;
2101                 let numeric_value: u64 = endian.parse(value);
2102                 let value = if i > 0 && numeric_value == 8 {
2103                     // Tolerate files written by old, buggy versions of PSPP
2104                     // where we believed that the value_length was repeated
2105                     // before each missing value.
2106                     read_bytes(&mut input)?
2107                 } else {
2108                     value
2109                 };
2110                 values.push(Value::String(RawStr(value)));
2111             }
2112             let missing_values = MissingValues {
2113                 values,
2114                 range: None,
2115             };
2116             missing_value_set.push(LongStringMissingValues {
2117                 var_name,
2118                 missing_values,
2119             });
2120         }
2121         Ok(Record::LongStringMissingValues(
2122             LongStringMissingValueRecord(missing_value_set),
2123         ))
2124     }
2125 }
2126
2127 impl LongStringMissingValueRecord<RawString, RawStr<8>> {
2128     pub fn decode(&self, decoder: &Decoder) -> LongStringMissingValueRecord<Identifier, String> {
2129         let mut mvs = Vec::with_capacity(self.0.len());
2130         for mv in self.0.iter() {
2131             if let Some(mv) = mv
2132                 .decode(decoder)
2133                 .map_err(Warning::InvalidLongStringMissingValueVariableName)
2134                 .issue_warning(&decoder.warn)
2135             {
2136                 mvs.push(mv);
2137             }
2138         }
2139         LongStringMissingValueRecord(mvs)
2140     }
2141 }
2142
2143 #[derive(Clone, Debug)]
2144 pub struct EncodingRecord(pub String);
2145
2146 impl ExtensionRecord for EncodingRecord {
2147     const SUBTYPE: u32 = 20;
2148     const SIZE: Option<u32> = Some(1);
2149     const COUNT: Option<u32> = None;
2150     const NAME: &'static str = "encoding record";
2151
2152     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Warning> {
2153         ext.check_size::<Self>()?;
2154
2155         Ok(Record::Encoding(EncodingRecord(
2156             String::from_utf8(ext.data.clone()).map_err(|_| Warning::BadEncodingName {
2157                 offset: ext.offsets.start,
2158             })?,
2159         )))
2160     }
2161 }
2162
2163 #[derive(Clone, Debug)]
2164 pub struct NumberOfCasesRecord {
2165     /// Always observed as 1.
2166     pub one: u64,
2167
2168     /// Number of cases.
2169     pub n_cases: u64,
2170 }
2171
2172 impl ExtensionRecord for NumberOfCasesRecord {
2173     const SUBTYPE: u32 = 16;
2174     const SIZE: Option<u32> = Some(8);
2175     const COUNT: Option<u32> = Some(2);
2176     const NAME: &'static str = "extended number of cases record";
2177
2178     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
2179         ext.check_size::<Self>()?;
2180
2181         let mut input = &ext.data[..];
2182         let one = endian.parse(read_bytes(&mut input)?);
2183         let n_cases = endian.parse(read_bytes(&mut input)?);
2184
2185         Ok(Record::NumberOfCases(NumberOfCasesRecord { one, n_cases }))
2186     }
2187 }
2188
2189 #[derive(Clone, Debug)]
2190 pub struct TextRecord {
2191     pub offsets: Range<u64>,
2192
2193     /// Type of record.
2194     pub rec_type: TextRecordType,
2195
2196     /// The text content of the record.
2197     pub text: RawString,
2198 }
2199
2200 #[derive(Clone, Copy, Debug)]
2201 pub enum TextRecordType {
2202     VariableSets,
2203     ProductInfo,
2204     LongNames,
2205     VeryLongStrings,
2206     FileAttributes,
2207     VariableAttributes,
2208 }
2209
2210 impl TextRecord {
2211     fn new(extension: Extension, rec_type: TextRecordType) -> Self {
2212         Self {
2213             offsets: extension.offsets,
2214             rec_type,
2215             text: extension.data.into(),
2216         }
2217     }
2218     pub fn decode(&self, decoder: &Decoder) -> DecodedRecord {
2219         match self.rec_type {
2220             TextRecordType::VariableSets => {
2221                 DecodedRecord::VariableSets(VariableSetRecord::decode(self, decoder))
2222             }
2223             TextRecordType::ProductInfo => {
2224                 DecodedRecord::ProductInfo(ProductInfoRecord::decode(self, decoder))
2225             }
2226             TextRecordType::LongNames => {
2227                 DecodedRecord::LongNames(LongNamesRecord::decode(self, decoder))
2228             }
2229             TextRecordType::VeryLongStrings => {
2230                 DecodedRecord::VeryLongStrings(VeryLongStringsRecord::decode(self, decoder))
2231             }
2232             TextRecordType::FileAttributes => {
2233                 DecodedRecord::FileAttributes(FileAttributeRecord::decode(self, decoder))
2234             }
2235             TextRecordType::VariableAttributes => {
2236                 DecodedRecord::VariableAttributes(VariableAttributeRecord::decode(self, decoder))
2237             }
2238         }
2239     }
2240 }
2241
2242 #[derive(Clone, Debug)]
2243 pub struct VeryLongString {
2244     pub short_name: Identifier,
2245     pub length: u16,
2246 }
2247
2248 impl VeryLongString {
2249     fn parse(decoder: &Decoder, input: &str) -> Result<VeryLongString, Warning> {
2250         let Some((short_name, length)) = input.split_once('=') else {
2251             return Err(Warning::TBD);
2252         };
2253         let short_name = decoder
2254             .new_identifier(short_name)
2255             .map_err(Warning::InvalidLongStringName)?;
2256         let length = length.parse().map_err(|_| Warning::TBD)?;
2257         Ok(VeryLongString { short_name, length })
2258     }
2259 }
2260
2261 #[derive(Clone, Debug)]
2262 pub struct VeryLongStringsRecord(Vec<VeryLongString>);
2263
2264 impl VeryLongStringsRecord {
2265     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2266         let input = decoder.decode(&source.text);
2267         let mut very_long_strings = Vec::new();
2268         for tuple in input
2269             .split('\0')
2270             .map(|s| s.trim_end_matches('\t'))
2271             .filter(|s| !s.is_empty())
2272         {
2273             if let Some(vls) = VeryLongString::parse(decoder, tuple).issue_warning(&decoder.warn) {
2274                 very_long_strings.push(vls)
2275             }
2276         }
2277         VeryLongStringsRecord(very_long_strings)
2278     }
2279 }
2280
2281 #[derive(Clone, Debug)]
2282 pub struct Attribute {
2283     pub name: Identifier,
2284     pub values: Vec<String>,
2285 }
2286
2287 impl Attribute {
2288     fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(Attribute, &'a str), Warning> {
2289         let Some((name, mut input)) = input.split_once('(') else {
2290             return Err(Warning::TBD);
2291         };
2292         let name = decoder
2293             .new_identifier(name)
2294             .map_err(Warning::InvalidAttributeName)?;
2295         let mut values = Vec::new();
2296         loop {
2297             let Some((value, rest)) = input.split_once('\n') else {
2298                 return Err(Warning::TBD);
2299             };
2300             if let Some(stripped) = value
2301                 .strip_prefix('\'')
2302                 .and_then(|value| value.strip_suffix('\''))
2303             {
2304                 values.push(stripped.into());
2305             } else {
2306                 decoder.warn(Warning::TBD);
2307                 values.push(value.into());
2308             }
2309             if let Some(rest) = rest.strip_prefix(')') {
2310                 let attribute = Attribute { name, values };
2311                 return Ok((attribute, rest));
2312             };
2313             input = rest;
2314         }
2315     }
2316 }
2317
2318 #[derive(Clone, Debug, Default)]
2319 pub struct AttributeSet(pub HashMap<Identifier, Vec<String>>);
2320
2321 impl AttributeSet {
2322     fn parse<'a>(
2323         decoder: &Decoder,
2324         mut input: &'a str,
2325         sentinel: Option<char>,
2326     ) -> Result<(AttributeSet, &'a str), Warning> {
2327         let mut attributes = HashMap::new();
2328         let rest = loop {
2329             match input.chars().next() {
2330                 None => break input,
2331                 c if c == sentinel => break &input[1..],
2332                 _ => {
2333                     let (attribute, rest) = Attribute::parse(decoder, input)?;
2334                     // XXX report duplicate name
2335                     attributes.insert(attribute.name, attribute.values);
2336                     input = rest;
2337                 }
2338             }
2339         };
2340         Ok((AttributeSet(attributes), rest))
2341     }
2342 }
2343
2344 #[derive(Clone, Debug, Default)]
2345 pub struct FileAttributeRecord(AttributeSet);
2346
2347 impl FileAttributeRecord {
2348     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2349         let input = decoder.decode(&source.text);
2350         match AttributeSet::parse(decoder, &input, None).issue_warning(&decoder.warn) {
2351             Some((set, rest)) => {
2352                 if !rest.is_empty() {
2353                     decoder.warn(Warning::TBD);
2354                 }
2355                 FileAttributeRecord(set)
2356             }
2357             None => FileAttributeRecord::default(),
2358         }
2359     }
2360 }
2361
2362 #[derive(Clone, Debug)]
2363 pub struct VarAttributeSet {
2364     pub long_var_name: Identifier,
2365     pub attributes: AttributeSet,
2366 }
2367
2368 impl VarAttributeSet {
2369     fn parse<'a>(decoder: &Decoder, input: &'a str) -> Result<(VarAttributeSet, &'a str), Warning> {
2370         let Some((long_var_name, rest)) = input.split_once(':') else {
2371             return Err(Warning::TBD);
2372         };
2373         let long_var_name = decoder
2374             .new_identifier(long_var_name)
2375             .map_err(Warning::InvalidAttributeVariableName)?;
2376         let (attributes, rest) = AttributeSet::parse(decoder, rest, Some('/'))?;
2377         let var_attribute = VarAttributeSet {
2378             long_var_name,
2379             attributes,
2380         };
2381         Ok((var_attribute, rest))
2382     }
2383 }
2384
2385 #[derive(Clone, Debug)]
2386 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
2387
2388 impl VariableAttributeRecord {
2389     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2390         let decoded = decoder.decode(&source.text);
2391         let mut input = decoded.as_ref();
2392         let mut var_attribute_sets = Vec::new();
2393         while !input.is_empty() {
2394             let Some((var_attribute, rest)) =
2395                 VarAttributeSet::parse(decoder, input).issue_warning(&decoder.warn)
2396             else {
2397                 break;
2398             };
2399             var_attribute_sets.push(var_attribute);
2400             input = rest;
2401         }
2402         VariableAttributeRecord(var_attribute_sets)
2403     }
2404 }
2405
2406 #[derive(Clone, Debug)]
2407 pub struct LongName {
2408     pub short_name: Identifier,
2409     pub long_name: Identifier,
2410 }
2411
2412 impl LongName {
2413     fn parse(input: &str, decoder: &Decoder) -> Result<Self, Warning> {
2414         let Some((short_name, long_name)) = input.split_once('=') else {
2415             return Err(Warning::TBD);
2416         };
2417         let short_name = decoder
2418             .new_identifier(short_name)
2419             .map_err(Warning::InvalidShortName)?;
2420         let long_name = decoder
2421             .new_identifier(long_name)
2422             .map_err(Warning::InvalidLongName)?;
2423         Ok(LongName {
2424             short_name,
2425             long_name,
2426         })
2427     }
2428 }
2429
2430 #[derive(Clone, Debug)]
2431 pub struct LongNamesRecord(Vec<LongName>);
2432
2433 impl LongNamesRecord {
2434     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2435         let input = decoder.decode(&source.text);
2436         let mut names = Vec::new();
2437         for pair in input.split('\t').filter(|s| !s.is_empty()) {
2438             if let Some(long_name) = LongName::parse(pair, decoder).issue_warning(&decoder.warn) {
2439                 names.push(long_name);
2440             }
2441         }
2442         LongNamesRecord(names)
2443     }
2444 }
2445
2446 #[derive(Clone, Debug)]
2447 pub struct ProductInfoRecord(pub String);
2448
2449 impl ProductInfoRecord {
2450     fn decode(source: &TextRecord, decoder: &Decoder) -> Self {
2451         Self(decoder.decode(&source.text).into())
2452     }
2453 }
2454 #[derive(Clone, Debug)]
2455 pub struct VariableSet {
2456     pub name: String,
2457     pub vars: Vec<Identifier>,
2458 }
2459
2460 impl VariableSet {
2461     fn parse(input: &str, decoder: &Decoder) -> Result<Self, Warning> {
2462         let (name, input) = input.split_once('=').ok_or(Warning::TBD)?;
2463         let mut vars = Vec::new();
2464         for var in input.split_ascii_whitespace() {
2465             if let Some(identifier) = decoder
2466                 .new_identifier(var)
2467                 .map_err(Warning::InvalidVariableSetName)
2468                 .issue_warning(&decoder.warn)
2469             {
2470                 vars.push(identifier);
2471             }
2472         }
2473         Ok(VariableSet {
2474             name: name.into(),
2475             vars,
2476         })
2477     }
2478 }
2479
2480 #[derive(Clone, Debug)]
2481 pub struct VariableSetRecord {
2482     pub offsets: Range<u64>,
2483     pub sets: Vec<VariableSet>,
2484 }
2485
2486 impl VariableSetRecord {
2487     fn decode(source: &TextRecord, decoder: &Decoder) -> VariableSetRecord {
2488         let mut sets = Vec::new();
2489         let input = decoder.decode(&source.text);
2490         for line in input.lines() {
2491             if let Some(set) = VariableSet::parse(line, decoder).issue_warning(&decoder.warn) {
2492                 sets.push(set)
2493             }
2494         }
2495         VariableSetRecord {
2496             offsets: source.offsets.clone(),
2497             sets,
2498         }
2499     }
2500 }
2501
2502 trait IssueWarning<T> {
2503     fn issue_warning<F>(self, warn: &F) -> Option<T>
2504     where
2505         F: Fn(Warning);
2506 }
2507 impl<T> IssueWarning<T> for Result<T, Warning> {
2508     fn issue_warning<F>(self, warn: &F) -> Option<T>
2509     where
2510         F: Fn(Warning),
2511     {
2512         match self {
2513             Ok(result) => Some(result),
2514             Err(error) => {
2515                 warn(error);
2516                 None
2517             }
2518         }
2519     }
2520 }
2521
2522 #[derive(Clone, Debug)]
2523 pub struct Extension {
2524     pub offsets: Range<u64>,
2525
2526     /// Record subtype.
2527     pub subtype: u32,
2528
2529     /// Size of each data element.
2530     pub size: u32,
2531
2532     /// Number of data elements.
2533     pub count: u32,
2534
2535     /// `size * count` bytes of data.
2536     pub data: Vec<u8>,
2537 }
2538
2539 impl Extension {
2540     fn check_size<E: ExtensionRecord>(&self) -> Result<(), Warning> {
2541         if let Some(expected_size) = E::SIZE {
2542             if self.size != expected_size {
2543                 return Err(Warning::BadRecordSize {
2544                     offset: self.offsets.start,
2545                     record: E::NAME.into(),
2546                     size: self.size,
2547                     expected_size,
2548                 });
2549             }
2550         }
2551         if let Some(expected_count) = E::COUNT {
2552             if self.count != expected_count {
2553                 return Err(Warning::BadRecordCount {
2554                     offset: self.offsets.start,
2555                     record: E::NAME.into(),
2556                     count: self.count,
2557                     expected_count,
2558                 });
2559             }
2560         }
2561         Ok(())
2562     }
2563
2564     fn read<R: Read + Seek>(
2565         r: &mut R,
2566         endian: Endian,
2567         n_vars: usize,
2568         warn: &dyn Fn(Warning),
2569     ) -> Result<Option<Record>, Error> {
2570         let subtype = endian.parse(read_bytes(r)?);
2571         let header_offset = r.stream_position()?;
2572         let size: u32 = endian.parse(read_bytes(r)?);
2573         let count = endian.parse(read_bytes(r)?);
2574         let Some(product) = size.checked_mul(count) else {
2575             return Err(Error::ExtensionRecordTooLarge {
2576                 offset: header_offset,
2577                 subtype,
2578                 size,
2579                 count,
2580             });
2581         };
2582         let start_offset = r.stream_position()?;
2583         let data = read_vec(r, product as usize)?;
2584         let end_offset = start_offset + product as u64;
2585         let extension = Extension {
2586             offsets: start_offset..end_offset,
2587             subtype,
2588             size,
2589             count,
2590             data,
2591         };
2592         let result = match subtype {
2593             IntegerInfoRecord::SUBTYPE => IntegerInfoRecord::parse(&extension, endian),
2594             FloatInfoRecord::SUBTYPE => FloatInfoRecord::parse(&extension, endian),
2595             VarDisplayRecord::SUBTYPE => VarDisplayRecord::parse(&extension, n_vars, endian, warn),
2596             MultipleResponseRecord::SUBTYPE | 19 => {
2597                 MultipleResponseRecord::parse(&extension, endian)
2598             }
2599             LongStringValueLabelRecord::SUBTYPE => {
2600                 LongStringValueLabelRecord::parse(&extension, endian)
2601             }
2602             EncodingRecord::SUBTYPE => EncodingRecord::parse(&extension, endian),
2603             NumberOfCasesRecord::SUBTYPE => NumberOfCasesRecord::parse(&extension, endian),
2604             5 => Ok(Record::Text(TextRecord::new(
2605                 extension,
2606                 TextRecordType::VariableSets,
2607             ))),
2608             10 => Ok(Record::Text(TextRecord::new(
2609                 extension,
2610                 TextRecordType::ProductInfo,
2611             ))),
2612             13 => Ok(Record::Text(TextRecord::new(
2613                 extension,
2614                 TextRecordType::LongNames,
2615             ))),
2616             14 => Ok(Record::Text(TextRecord::new(
2617                 extension,
2618                 TextRecordType::VeryLongStrings,
2619             ))),
2620             17 => Ok(Record::Text(TextRecord::new(
2621                 extension,
2622                 TextRecordType::FileAttributes,
2623             ))),
2624             18 => Ok(Record::Text(TextRecord::new(
2625                 extension,
2626                 TextRecordType::VariableAttributes,
2627             ))),
2628             _ => Ok(Record::OtherExtension(extension)),
2629         };
2630         match result {
2631             Ok(result) => Ok(Some(result)),
2632             Err(error) => {
2633                 warn(error);
2634                 Ok(None)
2635             }
2636         }
2637     }
2638 }
2639
2640 #[derive(Clone, Debug)]
2641 pub struct ZHeader {
2642     /// File offset to the start of the record.
2643     pub offset: u64,
2644
2645     /// File offset to the ZLIB data header.
2646     pub zheader_offset: u64,
2647
2648     /// File offset to the ZLIB trailer.
2649     pub ztrailer_offset: u64,
2650
2651     /// Length of the ZLIB trailer in bytes.
2652     pub ztrailer_len: u64,
2653 }
2654
2655 impl ZHeader {
2656     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
2657         let offset = r.stream_position()?;
2658         let zheader_offset: u64 = endian.parse(read_bytes(r)?);
2659         let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
2660         let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
2661
2662         Ok(ZHeader {
2663             offset,
2664             zheader_offset,
2665             ztrailer_offset,
2666             ztrailer_len,
2667         })
2668     }
2669 }
2670
2671 #[derive(Clone, Debug)]
2672 pub struct ZTrailer {
2673     /// File offset to the start of the record.
2674     pub offset: u64,
2675
2676     /// Compression bias as a negative integer, e.g. -100.
2677     pub int_bias: i64,
2678
2679     /// Always observed as zero.
2680     pub zero: u64,
2681
2682     /// Uncompressed size of each block, except possibly the last.  Only
2683     /// `0x3ff000` has been observed so far.
2684     pub block_size: u32,
2685
2686     /// Block descriptors, always `(ztrailer_len - 24) / 24)` of them.
2687     pub blocks: Vec<ZBlock>,
2688 }
2689
2690 #[derive(Clone, Debug)]
2691 pub struct ZBlock {
2692     /// Offset of block of data if simple compression were used.
2693     pub uncompressed_ofs: u64,
2694
2695     /// Actual offset within the file of the compressed data block.
2696     pub compressed_ofs: u64,
2697
2698     /// The number of bytes in this data block after decompression.  This is
2699     /// `block_size` in every data block but the last, which may be smaller.
2700     pub uncompressed_size: u32,
2701
2702     /// The number of bytes in this data block, as stored compressed in this
2703     /// file.
2704     pub compressed_size: u32,
2705 }
2706
2707 impl ZBlock {
2708     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
2709         Ok(ZBlock {
2710             uncompressed_ofs: endian.parse(read_bytes(r)?),
2711             compressed_ofs: endian.parse(read_bytes(r)?),
2712             uncompressed_size: endian.parse(read_bytes(r)?),
2713             compressed_size: endian.parse(read_bytes(r)?),
2714         })
2715     }
2716 }
2717
2718 impl ZTrailer {
2719     fn read<R: Read + Seek>(
2720         reader: &mut R,
2721         endian: Endian,
2722         ztrailer_ofs: u64,
2723         ztrailer_len: u64,
2724     ) -> Result<Option<ZTrailer>, Error> {
2725         let start_offset = reader.stream_position()?;
2726         if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
2727             return Ok(None);
2728         }
2729         let int_bias = endian.parse(read_bytes(reader)?);
2730         let zero = endian.parse(read_bytes(reader)?);
2731         let block_size = endian.parse(read_bytes(reader)?);
2732         let n_blocks: u32 = endian.parse(read_bytes(reader)?);
2733         let expected_n_blocks = (ztrailer_len - 24) / 24;
2734         if n_blocks as u64 != expected_n_blocks {
2735             return Err(Error::BadZlibTrailerNBlocks {
2736                 offset: ztrailer_ofs,
2737                 n_blocks,
2738                 expected_n_blocks,
2739                 ztrailer_len,
2740             });
2741         }
2742         let blocks = (0..n_blocks)
2743             .map(|_| ZBlock::read(reader, endian))
2744             .collect::<Result<Vec<_>, _>>()?;
2745         reader.seek(SeekFrom::Start(start_offset))?;
2746         Ok(Some(ZTrailer {
2747             offset: ztrailer_ofs,
2748             int_bias,
2749             zero,
2750             block_size,
2751             blocks,
2752         }))
2753     }
2754 }
2755
2756 fn try_read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<Option<[u8; N]>, IoError> {
2757     let mut buf = [0; N];
2758     let n = r.read(&mut buf)?;
2759     if n > 0 {
2760         if n < N {
2761             r.read_exact(&mut buf[n..])?;
2762         }
2763         Ok(Some(buf))
2764     } else {
2765         Ok(None)
2766     }
2767 }
2768
2769 fn read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<[u8; N], IoError> {
2770     let mut buf = [0; N];
2771     r.read_exact(&mut buf)?;
2772     Ok(buf)
2773 }
2774
2775 fn read_vec<R: Read>(r: &mut R, n: usize) -> Result<Vec<u8>, IoError> {
2776     let mut vec = vec![0; n];
2777     r.read_exact(&mut vec)?;
2778     Ok(vec)
2779 }
2780
2781 fn read_string<R: Read>(r: &mut R, endian: Endian) -> Result<RawString, IoError> {
2782     let length: u32 = endian.parse(read_bytes(r)?);
2783     Ok(read_vec(r, length as usize)?.into())
2784 }
2785
2786 #[derive(Clone, Debug)]
2787 pub struct LongStringValueLabels<N, S>
2788 where
2789     S: Debug,
2790 {
2791     pub var_name: N,
2792     pub width: u32,
2793
2794     /// `(value, label)` pairs, where each value is `width` bytes.
2795     pub labels: Vec<(S, S)>,
2796 }
2797
2798 impl LongStringValueLabels<RawString, RawString> {
2799     fn decode<'a>(
2800         &'a self,
2801         decoder: &Decoder,
2802     ) -> Result<LongStringValueLabels<Identifier, Cow<'a, str>>, Warning> {
2803         let var_name = decoder.decode(&self.var_name);
2804         let var_name = Identifier::new(var_name.trim_end(), decoder.encoding)
2805             .map_err(Warning::InvalidLongStringValueLabelName)?;
2806
2807         let mut labels = Vec::with_capacity(self.labels.len());
2808         for (value, label) in self.labels.iter() {
2809             let value = decoder.decode_exact_length(&value.0);
2810             let label = decoder.decode(label);
2811             labels.push((value, label));
2812         }
2813
2814         Ok(LongStringValueLabels {
2815             var_name,
2816             width: self.width,
2817             labels,
2818         })
2819     }
2820 }
2821
2822 #[derive(Clone, Debug)]
2823 pub struct LongStringValueLabelRecord<N, S>(pub Vec<LongStringValueLabels<N, S>>)
2824 where
2825     N: Debug,
2826     S: Debug;
2827
2828 impl ExtensionRecord for LongStringValueLabelRecord<RawString, RawString> {
2829     const SUBTYPE: u32 = 21;
2830     const SIZE: Option<u32> = Some(1);
2831     const COUNT: Option<u32> = None;
2832     const NAME: &'static str = "long string value labels record";
2833
2834     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Warning> {
2835         ext.check_size::<Self>()?;
2836
2837         let mut input = &ext.data[..];
2838         let mut label_set = Vec::new();
2839         while !input.is_empty() {
2840             let var_name = read_string(&mut input, endian)?;
2841             let width: u32 = endian.parse(read_bytes(&mut input)?);
2842             let n_labels: u32 = endian.parse(read_bytes(&mut input)?);
2843             let mut labels = Vec::new();
2844             for _ in 0..n_labels {
2845                 let value = read_string(&mut input, endian)?;
2846                 let label = read_string(&mut input, endian)?;
2847                 labels.push((value, label));
2848             }
2849             label_set.push(LongStringValueLabels {
2850                 var_name,
2851                 width,
2852                 labels,
2853             })
2854         }
2855         Ok(Record::LongStringValueLabels(LongStringValueLabelRecord(
2856             label_set,
2857         )))
2858     }
2859 }
2860
2861 impl LongStringValueLabelRecord<RawString, RawString> {
2862     fn decode<'a>(
2863         &'a self,
2864         decoder: &Decoder,
2865     ) -> LongStringValueLabelRecord<Identifier, Cow<'a, str>> {
2866         let mut labels = Vec::with_capacity(self.0.len());
2867         for label in &self.0 {
2868             match label.decode(decoder) {
2869                 Ok(set) => labels.push(set),
2870                 Err(error) => decoder.warn(error),
2871             }
2872         }
2873         LongStringValueLabelRecord(labels)
2874     }
2875 }