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