ac2d1960acab3c9f03cfcc682666699acfbe748d
[pspp] / rust / src / raw.rs
1 use crate::endian::{Endian, Parse, ToBytes};
2
3 use encoding_rs::{mem::decode_latin1, DecoderResult, Encoding};
4 use flate2::read::ZlibDecoder;
5 use num::Integer;
6 use std::{
7     borrow::Cow,
8     cell::RefCell,
9     cmp::Ordering,
10     collections::VecDeque,
11     fmt::{Debug, Display, Formatter, Result as FmtResult},
12     io::{Error as IoError, Read, Seek, SeekFrom},
13     iter::repeat,
14     mem::take,
15     ops::Range,
16     rc::Rc,
17     str::from_utf8,
18 };
19 use thiserror::Error as ThisError;
20
21 #[derive(ThisError, Debug)]
22 pub enum Error {
23     #[error("Not an SPSS system file")]
24     NotASystemFile,
25
26     #[error("Invalid magic number {0:?}")]
27     BadMagic([u8; 4]),
28
29     #[error("I/O error ({0})")]
30     Io(#[from] IoError),
31
32     #[error("Invalid SAV compression code {0}")]
33     InvalidSavCompression(u32),
34
35     #[error("Invalid ZSAV compression code {0}")]
36     InvalidZsavCompression(u32),
37
38     #[error("Variable record at offset {offset:#x} specifies width {width} not in valid range [-1,255).")]
39     BadVariableWidth { offset: u64, width: i32 },
40
41     #[error("Document record at offset {offset:#x} has document line count ({n}) greater than the maximum number {max}.")]
42     BadDocumentLength { offset: u64, n: usize, max: usize },
43
44     #[error("At offset {offset:#x}, unrecognized record type {rec_type}.")]
45     BadRecordType { offset: u64, rec_type: u32 },
46
47     #[error("In variable record starting at offset {start_offset:#x}, variable label code {code} at offset {code_offset:#x} is not 0 or 1.")]
48     BadVariableLabelCode {
49         start_offset: u64,
50         code_offset: u64,
51         code: u32,
52     },
53
54     #[error(
55         "At offset {offset:#x}, numeric missing value code ({code}) is not -3, -2, 0, 1, 2, or 3."
56     )]
57     BadNumericMissingValueCode { offset: u64, code: i32 },
58
59     #[error("At offset {offset:#x}, string missing value code ({code}) is not 0, 1, 2, or 3.")]
60     BadStringMissingValueCode { offset: u64, code: i32 },
61
62     #[error("At offset {offset:#x}, number of value labels ({n}) is greater than the maximum number {max}.")]
63     BadNumberOfValueLabels { offset: u64, n: u32, max: u32 },
64
65     #[error("At offset {offset:#x}, following value label record, found record type {rec_type} instead of expected type 4 for variable index record")]
66     ExpectedVarIndexRecord { offset: u64, rec_type: u32 },
67
68     #[error("At offset {offset:#x}, number of variables indexes for value labels ({n}) is greater than the maximum number ({max}).")]
69     TooManyVarIndexes { offset: u64, n: u32, max: u32 },
70
71     #[error("At offset {offset:#x}, at least one valid variable index for value labels is required but none were specified.")]
72     NoVarIndexes { offset: u64 },
73
74     #[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())]
75     MixedVarTypes {
76         offset: u64,
77         var_type: VarType,
78         wrong_types: Vec<u32>,
79     },
80
81     #[error("At offset {offset:#x}, one or more variable indexes for value labels were not in the valid range [1,{max}]: {invalid:?}")]
82     InvalidVarIndexes {
83         offset: u64,
84         max: usize,
85         invalid: Vec<u32>,
86     },
87
88     #[error("At offset {offset:#x}, record type 7 subtype {subtype} is too large with element size {size} and {count} elements.")]
89     ExtensionRecordTooLarge {
90         offset: u64,
91         subtype: u32,
92         size: u32,
93         count: u32,
94     },
95
96     #[error("Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a {case_len}-byte case.")]
97     EofInCase {
98         offset: u64,
99         case_ofs: u64,
100         case_len: usize,
101     },
102
103     #[error(
104         "Unexpected end of file at offset {offset:#x}, {case_ofs} bytes into a compressed case."
105     )]
106     EofInCompressedCase { offset: u64, case_ofs: u64 },
107
108     #[error("Data ends at offset {offset:#x}, {case_ofs} bytes into a compressed case.")]
109     PartialCompressedCase { offset: u64, case_ofs: u64 },
110
111     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a string was found where a number was expected.")]
112     CompressedNumberExpected { offset: u64, case_ofs: u64 },
113
114     #[error("At {case_ofs} bytes into compressed case starting at offset {offset:#x}, a number was found where a string was expected.")]
115     CompressedStringExpected { offset: u64, case_ofs: u64 },
116
117     #[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}.")]
118     BadZlibTrailerNBlocks {
119         offset: u64,
120         n_blocks: u32,
121         expected_n_blocks: u64,
122         ztrailer_len: u64,
123     },
124
125     #[error("At offset {offset:#x}, {record} has bad size {size} bytes instead of the expected {expected_size}.")]
126     BadRecordSize {
127         offset: u64,
128         record: String,
129         size: u32,
130         expected_size: u32,
131     },
132
133     #[error("At offset {offset:#x}, {record} has bad count {count} instead of the expected {expected_count}.")]
134     BadRecordCount {
135         offset: u64,
136         record: String,
137         count: u32,
138         expected_count: u32,
139     },
140
141     #[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.")]
142     BadLongMissingValueLength {
143         record_offset: u64,
144         offset: u64,
145         value_len: u32,
146     },
147
148     #[error("The encoding record at offset {offset:#x} contains an encoding name that is not valid UTF-8.")]
149     BadEncodingName { offset: u64 },
150
151     // XXX This is risky because `text` might be arbitarily long.
152     #[error("Text string contains invalid bytes for {encoding} encoding: {text}")]
153     MalformedString { encoding: String, text: String },
154
155     #[error("Details TBD")]
156     TBD,
157 }
158
159 #[derive(Clone, Debug)]
160 pub enum Record {
161     Header(HeaderRecord<RawString>),
162     Variable(VariableRecord<RawString, RawStr<8>>),
163     ValueLabel(ValueLabelRecord<RawStr<8>, RawString>),
164     Document(DocumentRecord<RawDocumentLine>),
165     IntegerInfo(IntegerInfoRecord),
166     FloatInfo(FloatInfoRecord),
167     VariableSets(TextRecord),
168     VarDisplay(VarDisplayRecord),
169     MultipleResponse(MultipleResponseRecord),
170     LongStringValueLabels(LongStringValueLabelRecord),
171     LongStringMissingValues(LongStringMissingValueRecord),
172     Encoding(EncodingRecord),
173     NumberOfCases(NumberOfCasesRecord),
174     ProductInfo(TextRecord),
175     LongNames(TextRecord),
176     VeryLongStrings(TextRecord),
177     FileAttributes(TextRecord),
178     VariableAttributes(TextRecord),
179     OtherExtension(Extension),
180     EndOfHeaders(u32),
181     ZHeader(ZHeader),
182     ZTrailer(ZTrailer),
183     Cases(Rc<RefCell<Cases>>),
184 }
185
186 impl Record {
187     fn read<R>(
188         reader: &mut R,
189         endian: Endian,
190         var_types: &[VarType],
191         warn: &Box<dyn Fn(Error)>,
192     ) -> Result<Option<Record>, Error>
193     where
194         R: Read + Seek,
195     {
196         let rec_type: u32 = endian.parse(read_bytes(reader)?);
197         match rec_type {
198             2 => Ok(Some(VariableRecord::read(reader, endian)?)),
199             3 => Ok(ValueLabelRecord::read(reader, endian, var_types, warn)?),
200             6 => Ok(Some(DocumentRecord::read(reader, endian)?)),
201             7 => Extension::read(reader, endian, warn),
202             999 => Ok(Some(Record::EndOfHeaders(
203                 endian.parse(read_bytes(reader)?),
204             ))),
205             _ => Err(Error::BadRecordType {
206                 offset: reader.stream_position()?,
207                 rec_type,
208             }),
209         }
210     }
211 }
212
213 // If `s` is valid UTF-8, returns it decoded as UTF-8, otherwise returns it
214 // decoded as Latin-1 (actually bytes interpreted as Unicode code points).
215 fn default_decode(s: &[u8]) -> Cow<str> {
216     from_utf8(s).map_or_else(|_| decode_latin1(s), Cow::from)
217 }
218
219 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
220 pub enum Compression {
221     Simple,
222     ZLib,
223 }
224
225 trait Header {
226     fn offsets(&self) -> Range<u64>;
227 }
228
229 #[derive(Clone)]
230 pub struct HeaderRecord<S>
231 where
232     S: Debug,
233 {
234     /// Offset in file.
235     pub offsets: Range<u64>,
236
237     /// Magic number.
238     pub magic: Magic,
239
240     /// Eye-catcher string, product name, in the file's encoding.  Padded
241     /// on the right with spaces.
242     pub eye_catcher: S,
243
244     /// Layout code, normally either 2 or 3.
245     pub layout_code: u32,
246
247     /// Number of variable positions, or `None` if the value in the file is
248     /// questionably trustworthy.
249     pub nominal_case_size: Option<u32>,
250
251     /// Compression type, if any,
252     pub compression: Option<Compression>,
253
254     /// 1-based variable index of the weight variable, or `None` if the file is
255     /// unweighted.
256     pub weight_index: Option<u32>,
257
258     /// Claimed number of cases, if known.
259     pub n_cases: Option<u32>,
260
261     /// Compression bias, usually 100.0.
262     pub bias: f64,
263
264     /// `dd mmm yy` in the file's encoding.
265     pub creation_date: S,
266
267     /// `HH:MM:SS` in the file's encoding.
268     pub creation_time: S,
269
270     /// File label, in the file's encoding.  Padded on the right with spaces.
271     pub file_label: S,
272
273     /// Endianness of the data in the file header.
274     pub endian: Endian,
275 }
276
277 impl<S> HeaderRecord<S>
278 where
279     S: Debug,
280 {
281     fn debug_field<T>(&self, f: &mut Formatter, name: &str, value: T) -> FmtResult
282     where
283         T: Debug,
284     {
285         writeln!(f, "{name:>17}: {:?}", value)
286     }
287 }
288
289 impl<S> Debug for HeaderRecord<S>
290 where
291     S: Debug,
292 {
293     fn fmt(&self, f: &mut Formatter) -> FmtResult {
294         writeln!(f, "File header record:")?;
295         self.debug_field(f, "Magic", self.magic)?;
296         self.debug_field(f, "Product name", &self.eye_catcher)?;
297         self.debug_field(f, "Layout code", self.layout_code)?;
298         self.debug_field(f, "Nominal case size", self.nominal_case_size)?;
299         self.debug_field(f, "Compression", self.compression)?;
300         self.debug_field(f, "Weight index", self.weight_index)?;
301         self.debug_field(f, "Number of cases", self.n_cases)?;
302         self.debug_field(f, "Compression bias", self.bias)?;
303         self.debug_field(f, "Creation date", &self.creation_date)?;
304         self.debug_field(f, "Creation time", &self.creation_time)?;
305         self.debug_field(f, "File label", &self.file_label)?;
306         self.debug_field(f, "Endianness", self.endian)
307     }
308 }
309
310 impl HeaderRecord<RawString> {
311     fn read<R: Read + Seek>(r: &mut R) -> Result<Self, Error> {
312         let start = r.stream_position()?;
313
314         let magic: [u8; 4] = read_bytes(r)?;
315         let magic: Magic = magic.try_into().map_err(|_| Error::NotASystemFile)?;
316
317         let eye_catcher = RawString(read_vec(r, 60)?);
318         let layout_code: [u8; 4] = read_bytes(r)?;
319         let endian = Endian::identify_u32(2, layout_code)
320             .or_else(|| Endian::identify_u32(2, layout_code))
321             .ok_or_else(|| Error::NotASystemFile)?;
322         let layout_code = endian.parse(layout_code);
323
324         let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
325         let nominal_case_size =
326             (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
327
328         let compression_code: u32 = endian.parse(read_bytes(r)?);
329         let compression = match (magic, compression_code) {
330             (Magic::Zsav, 2) => Some(Compression::ZLib),
331             (Magic::Zsav, code) => return Err(Error::InvalidZsavCompression(code)),
332             (_, 0) => None,
333             (_, 1) => Some(Compression::Simple),
334             (_, code) => return Err(Error::InvalidSavCompression(code)),
335         };
336
337         let weight_index: u32 = endian.parse(read_bytes(r)?);
338         let weight_index = (weight_index > 0).then_some(weight_index);
339
340         let n_cases: u32 = endian.parse(read_bytes(r)?);
341         let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
342
343         let bias: f64 = endian.parse(read_bytes(r)?);
344
345         let creation_date = RawString(read_vec(r, 9)?);
346         let creation_time = RawString(read_vec(r, 8)?);
347         let file_label = RawString(read_vec(r, 64)?);
348         let _: [u8; 3] = read_bytes(r)?;
349
350         Ok(HeaderRecord {
351             offsets: start..r.stream_position()?,
352             magic,
353             layout_code,
354             nominal_case_size,
355             compression,
356             weight_index,
357             n_cases,
358             bias,
359             creation_date,
360             creation_time,
361             eye_catcher,
362             file_label,
363             endian,
364         })
365     }
366
367     fn decode<'a>(&'a self, decoder: &Decoder) -> HeaderRecord<Cow<'a, str>> {
368         let eye_catcher = decoder.decode(&self.eye_catcher);
369         let file_label = decoder.decode(&self.file_label);
370         let creation_date = decoder.decode(&self.creation_date);
371         let creation_time = decoder.decode(&self.creation_time);
372         HeaderRecord {
373             eye_catcher,
374             weight_index: self.weight_index,
375             n_cases: self.n_cases,
376             file_label,
377             offsets: self.offsets.clone(),
378             magic: self.magic,
379             layout_code: self.layout_code,
380             nominal_case_size: self.nominal_case_size,
381             compression: self.compression,
382             bias: self.bias,
383             creation_date,
384             creation_time,
385             endian: self.endian,
386         }
387     }
388 }
389
390 struct Decoder {
391     encoding: &'static Encoding,
392     warn: Box<dyn Fn(Error)>,
393 }
394
395 impl Decoder {
396     fn decode_slice<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
397         let (output, malformed) = self.encoding.decode_without_bom_handling(input);
398         if malformed {
399             (self.warn)(Error::MalformedString {
400                 encoding: self.encoding.name().into(),
401                 text: output.clone().into(),
402             });
403         }
404         output
405     }
406         
407     fn decode<'a>(&self, input: &'a RawString) -> Cow<'a, str> {
408         self.decode_slice(input.0.as_slice())
409     }
410
411     /// Returns `input` decoded from `self.encoding` into UTF-8 such that
412     /// re-encoding the result back into `self.encoding` will have exactly the
413     /// same length in bytes.
414     ///
415     /// XXX warn about errors?
416     fn decode_exact_length<'a>(&self, input: &'a [u8]) -> Cow<'a, str> {
417         if let (s, false) = self.encoding.decode_without_bom_handling(input) {
418             // This is the common case.  Usually there will be no errors.
419             s
420         } else {
421             // Unusual case.  Don't bother to optimize it much.
422             let mut decoder = self.encoding.new_decoder_without_bom_handling();
423             let mut output = String::with_capacity(
424                 decoder
425                     .max_utf8_buffer_length_without_replacement(input.len())
426                     .unwrap(),
427             );
428             let mut rest = input;
429             while !rest.is_empty() {
430                 match decoder.decode_to_string_without_replacement(rest, &mut output, true) {
431                     (DecoderResult::InputEmpty, _) => break,
432                     (DecoderResult::OutputFull, _) => unreachable!(),
433                     (DecoderResult::Malformed(a, b), consumed) => {
434                         let skipped = a as usize + b as usize;
435                         output.extend(repeat('?').take(skipped));
436                         rest = &rest[consumed..];
437                     }
438                 }
439             }
440             assert_eq!(self.encoding.encode(&output).0.len(), input.len());
441             output.into()
442         }
443     }
444 }
445
446 impl<S> Header for HeaderRecord<S>
447 where
448     S: Debug,
449 {
450     fn offsets(&self) -> Range<u64> {
451         self.offsets.clone()
452     }
453 }
454
455 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
456 pub enum Magic {
457     /// Regular system file.
458     Sav,
459
460     /// System file with Zlib-compressed data.
461     Zsav,
462
463     /// EBCDIC-encoded system file.
464     Ebcdic,
465 }
466
467 impl Magic {
468     /// Magic number for a regular system file.
469     pub const SAV: [u8; 4] = *b"$FL2";
470
471     /// Magic number for a system file that contains zlib-compressed data.
472     pub const ZSAV: [u8; 4] = *b"$FL3";
473
474     /// Magic number for an EBCDIC-encoded system file.  This is `$FL2` encoded
475     /// in EBCDIC.
476     pub const EBCDIC: [u8; 4] = [0x5b, 0xc6, 0xd3, 0xf2];
477 }
478
479 impl Debug for Magic {
480     fn fmt(&self, f: &mut Formatter) -> FmtResult {
481         let s = match *self {
482             Magic::Sav => "$FL2",
483             Magic::Zsav => "$FL3",
484             Magic::Ebcdic => "($FL2 in EBCDIC)",
485         };
486         write!(f, "{s}")
487     }
488 }
489
490 impl TryFrom<[u8; 4]> for Magic {
491     type Error = Error;
492
493     fn try_from(value: [u8; 4]) -> Result<Self, Self::Error> {
494         match value {
495             Magic::SAV => Ok(Magic::Sav),
496             Magic::ZSAV => Ok(Magic::Zsav),
497             Magic::EBCDIC => Ok(Magic::Ebcdic),
498             _ => Err(Error::BadMagic(value)),
499         }
500     }
501 }
502
503 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
504 pub enum VarType {
505     Numeric,
506     String,
507 }
508
509 impl VarType {
510     fn from_width(width: i32) -> VarType {
511         match width {
512             0 => VarType::Numeric,
513             _ => VarType::String,
514         }
515     }
516
517     fn opposite(self) -> VarType {
518         match self {
519             Self::Numeric => Self::String,
520             Self::String => Self::Numeric,
521         }
522     }
523 }
524
525 impl Display for VarType {
526     fn fmt(&self, f: &mut Formatter) -> FmtResult {
527         match self {
528             VarType::Numeric => write!(f, "numeric"),
529             VarType::String => write!(f, "string"),
530         }
531     }
532 }
533
534 #[derive(Copy, Clone)]
535 pub enum Value<S>
536 where
537     S: Debug,
538 {
539     Number(Option<f64>),
540     String(S),
541 }
542
543 type RawValue = Value<RawStr<8>>;
544
545 impl<S> Debug for Value<S>
546 where
547     S: Debug,
548 {
549     fn fmt(&self, f: &mut Formatter) -> FmtResult {
550         match self {
551             Value::Number(Some(number)) => write!(f, "{number:?}"),
552             Value::Number(None) => write!(f, "SYSMIS"),
553             Value::String(s) => write!(f, "{:?}", s),
554         }
555     }
556 }
557
558 impl RawValue {
559     fn read<R: Read>(r: &mut R, var_type: VarType, endian: Endian) -> Result<Self, IoError> {
560         Ok(Self::from_raw(
561             &UntypedValue(read_bytes(r)?),
562             var_type,
563             endian,
564         ))
565     }
566
567     pub fn from_raw(raw: &UntypedValue, var_type: VarType, endian: Endian) -> Self {
568         match var_type {
569             VarType::String => Value::String(RawStr(raw.0)),
570             VarType::Numeric => {
571                 let number: f64 = endian.parse(raw.0);
572                 Value::Number((number != -f64::MAX).then_some(number))
573             }
574         }
575     }
576
577     fn read_case<R: Read + Seek>(
578         reader: &mut R,
579         var_types: &[VarType],
580         endian: Endian,
581     ) -> Result<Option<Vec<Self>>, Error> {
582         let case_start = reader.stream_position()?;
583         let mut values = Vec::with_capacity(var_types.len());
584         for (i, &var_type) in var_types.iter().enumerate() {
585             let Some(raw) = try_read_bytes(reader)? else {
586                 if i == 0 {
587                     return Ok(None);
588                 } else {
589                     let offset = reader.stream_position()?;
590                     return Err(Error::EofInCase {
591                         offset,
592                         case_ofs: offset - case_start,
593                         case_len: var_types.len() * 8,
594                     });
595                 }
596             };
597             values.push(Value::from_raw(&UntypedValue(raw), var_type, endian));
598         }
599         Ok(Some(values))
600     }
601
602     fn read_compressed_case<R: Read + Seek>(
603         reader: &mut R,
604         var_types: &[VarType],
605         codes: &mut VecDeque<u8>,
606         endian: Endian,
607         bias: f64,
608     ) -> Result<Option<Vec<Self>>, Error> {
609         let case_start = reader.stream_position()?;
610         let mut values = Vec::with_capacity(var_types.len());
611         for (i, &var_type) in var_types.iter().enumerate() {
612             let value = loop {
613                 let Some(code) = codes.pop_front() else {
614                     let Some(new_codes): Option<[u8; 8]> = try_read_bytes(reader)? else {
615                         if i == 0 {
616                             return Ok(None);
617                         } else {
618                             let offset = reader.stream_position()?;
619                             return Err(Error::EofInCompressedCase {
620                                 offset,
621                                 case_ofs: offset - case_start,
622                             });
623                         }
624                     };
625                     codes.extend(new_codes.into_iter());
626                     continue;
627                 };
628                 match code {
629                     0 => (),
630                     1..=251 => match var_type {
631                         VarType::Numeric => break Self::Number(Some(code as f64 - bias)),
632                         VarType::String => {
633                             break Self::String(RawStr(endian.to_bytes(code as f64 - bias)))
634                         }
635                     },
636                     252 => {
637                         if i == 0 {
638                             return Ok(None);
639                         } else {
640                             let offset = reader.stream_position()?;
641                             return Err(Error::PartialCompressedCase {
642                                 offset,
643                                 case_ofs: offset - case_start,
644                             });
645                         }
646                     }
647                     253 => {
648                         break Self::from_raw(&UntypedValue(read_bytes(reader)?), var_type, endian)
649                     }
650                     254 => match var_type {
651                         VarType::String => break Self::String(RawStr(*b"        ")), // XXX EBCDIC
652                         VarType::Numeric => {
653                             return Err(Error::CompressedStringExpected {
654                                 offset: case_start,
655                                 case_ofs: reader.stream_position()? - case_start,
656                             })
657                         }
658                     },
659                     255 => match var_type {
660                         VarType::Numeric => break Self::Number(None),
661                         VarType::String => {
662                             return Err(Error::CompressedNumberExpected {
663                                 offset: case_start,
664                                 case_ofs: reader.stream_position()? - case_start,
665                             })
666                         }
667                     },
668                 }
669             };
670             values.push(value);
671         }
672         Ok(Some(values))
673     }
674
675     fn decode(&self, decoder: &Decoder) -> Value<String> {
676         match self {
677             Self::Number(x) => Value::Number(*x),
678             Self::String(s) => Value::String(decoder.decode_exact_length(&s.0).into()),
679         }
680     }
681 }
682
683 struct ZlibDecodeMultiple<R>
684 where
685     R: Read + Seek,
686 {
687     reader: Option<ZlibDecoder<R>>,
688 }
689
690 impl<R> ZlibDecodeMultiple<R>
691 where
692     R: Read + Seek,
693 {
694     fn new(reader: R) -> ZlibDecodeMultiple<R> {
695         ZlibDecodeMultiple {
696             reader: Some(ZlibDecoder::new(reader)),
697         }
698     }
699 }
700
701 impl<R> Read for ZlibDecodeMultiple<R>
702 where
703     R: Read + Seek,
704 {
705     fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
706         loop {
707             match self.reader.as_mut().unwrap().read(buf)? {
708                 0 => {
709                     let inner = self.reader.take().unwrap().into_inner();
710                     self.reader = Some(ZlibDecoder::new(inner));
711                 }
712                 n => return Ok(n),
713             };
714         }
715     }
716 }
717
718 impl<R> Seek for ZlibDecodeMultiple<R>
719 where
720     R: Read + Seek,
721 {
722     fn seek(&mut self, pos: SeekFrom) -> Result<u64, IoError> {
723         self.reader.as_mut().unwrap().get_mut().seek(pos)
724     }
725 }
726
727 enum ReaderState {
728     Start,
729     Headers,
730     ZlibHeader,
731     ZlibTrailer {
732         ztrailer_offset: u64,
733         ztrailer_len: u64,
734     },
735     Cases,
736     End,
737 }
738
739 pub struct Reader<R>
740 where
741     R: Read + Seek + 'static,
742 {
743     reader: Option<R>,
744     warn: Box<dyn Fn(Error)>,
745
746     header: HeaderRecord<RawString>,
747     var_types: Vec<VarType>,
748
749     state: ReaderState,
750 }
751
752 impl<R> Reader<R>
753 where
754     R: Read + Seek + 'static,
755 {
756     pub fn new<F>(mut reader: R, warn: F) -> Result<Self, Error>
757     where
758         F: Fn(Error) + 'static,
759     {
760         let header = HeaderRecord::read(&mut reader)?;
761         Ok(Self {
762             reader: Some(reader),
763             warn: Box::new(warn),
764             header,
765             var_types: Vec::new(),
766             state: ReaderState::Start,
767         })
768     }
769     fn cases(&mut self) -> Cases {
770         self.state = ReaderState::End;
771         Cases::new(
772             self.reader.take().unwrap(),
773             take(&mut self.var_types),
774             &self.header,
775         )
776     }
777 }
778
779 impl<R> Iterator for Reader<R>
780 where
781     R: Read + Seek + 'static,
782 {
783     type Item = Result<Record, Error>;
784
785     fn next(&mut self) -> Option<Self::Item> {
786         match self.state {
787             ReaderState::Start => {
788                 self.state = ReaderState::Headers;
789                 Some(Ok(Record::Header(self.header.clone())))
790             }
791             ReaderState::Headers => {
792                 let record = loop {
793                     match Record::read(
794                         self.reader.as_mut().unwrap(),
795                         self.header.endian,
796                         self.var_types.as_slice(),
797                         &self.warn,
798                     ) {
799                         Ok(Some(record)) => break record,
800                         Ok(None) => (),
801                         Err(error) => return Some(Err(error)),
802                     }
803                 };
804                 match record {
805                     Record::Variable(VariableRecord { width, .. }) => {
806                         self.var_types.push(VarType::from_width(width));
807                     }
808                     Record::EndOfHeaders(_) => {
809                         self.state = if let Some(Compression::ZLib) = self.header.compression {
810                             ReaderState::ZlibHeader
811                         } else {
812                             ReaderState::Cases
813                         };
814                     }
815                     _ => (),
816                 };
817                 Some(Ok(record))
818             }
819             ReaderState::ZlibHeader => {
820                 let zheader = match ZHeader::read(self.reader.as_mut().unwrap(), self.header.endian)
821                 {
822                     Ok(zheader) => zheader,
823                     Err(error) => return Some(Err(error)),
824                 };
825                 self.state = ReaderState::ZlibTrailer {
826                     ztrailer_offset: zheader.ztrailer_offset,
827                     ztrailer_len: zheader.ztrailer_len,
828                 };
829                 Some(Ok(Record::ZHeader(zheader)))
830             }
831             ReaderState::ZlibTrailer {
832                 ztrailer_offset,
833                 ztrailer_len,
834             } => {
835                 match ZTrailer::read(
836                     self.reader.as_mut().unwrap(),
837                     self.header.endian,
838                     ztrailer_offset,
839                     ztrailer_len,
840                 ) {
841                     Ok(None) => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
842                     Ok(Some(ztrailer)) => Some(Ok(Record::ZTrailer(ztrailer))),
843                     Err(error) => Some(Err(error)),
844                 }
845             }
846             ReaderState::Cases => Some(Ok(Record::Cases(Rc::new(RefCell::new(self.cases()))))),
847             ReaderState::End => None,
848         }
849     }
850 }
851
852 trait ReadSeek: Read + Seek {}
853 impl<T> ReadSeek for T where T: Read + Seek {}
854
855 pub struct Cases {
856     reader: Box<dyn ReadSeek>,
857     var_types: Vec<VarType>,
858     compression: Option<Compression>,
859     bias: f64,
860     endian: Endian,
861     codes: VecDeque<u8>,
862     eof: bool,
863 }
864
865 impl Debug for Cases {
866     fn fmt(&self, f: &mut Formatter) -> FmtResult {
867         write!(f, "Cases")
868     }
869 }
870
871 impl Cases {
872     fn new<R>(reader: R, var_types: Vec<VarType>, header: &HeaderRecord<RawString>) -> Self
873     where
874         R: Read + Seek + 'static,
875     {
876         Self {
877             reader: if header.compression == Some(Compression::ZLib) {
878                 Box::new(ZlibDecodeMultiple::new(reader))
879             } else {
880                 Box::new(reader)
881             },
882             var_types,
883             compression: header.compression,
884             bias: header.bias,
885             endian: header.endian,
886             codes: VecDeque::with_capacity(8),
887             eof: false,
888         }
889     }
890 }
891
892 impl Iterator for Cases {
893     type Item = Result<Vec<RawValue>, Error>;
894
895     fn next(&mut self) -> Option<Self::Item> {
896         if self.eof {
897             return None;
898         }
899
900         let retval = if self.compression.is_some() {
901             Value::read_compressed_case(
902                 &mut self.reader,
903                 &self.var_types,
904                 &mut self.codes,
905                 self.endian,
906                 self.bias,
907             )
908             .transpose()
909         } else {
910             Value::read_case(&mut self.reader, &self.var_types, self.endian).transpose()
911         };
912         self.eof = matches!(retval, None | Some(Err(_)));
913         retval
914     }
915 }
916
917 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
918 pub struct Spec(pub u32);
919
920 impl Debug for Spec {
921     fn fmt(&self, f: &mut Formatter) -> FmtResult {
922         let type_ = format_name(self.0 >> 16);
923         let w = (self.0 >> 8) & 0xff;
924         let d = self.0 & 0xff;
925         write!(f, "{:06x} ({type_}{w}.{d})", self.0)
926     }
927 }
928
929 fn format_name(type_: u32) -> Cow<'static, str> {
930     match type_ {
931         1 => "A",
932         2 => "AHEX",
933         3 => "COMMA",
934         4 => "DOLLAR",
935         5 => "F",
936         6 => "IB",
937         7 => "PIBHEX",
938         8 => "P",
939         9 => "PIB",
940         10 => "PK",
941         11 => "RB",
942         12 => "RBHEX",
943         15 => "Z",
944         16 => "N",
945         17 => "E",
946         20 => "DATE",
947         21 => "TIME",
948         22 => "DATETIME",
949         23 => "ADATE",
950         24 => "JDATE",
951         25 => "DTIME",
952         26 => "WKDAY",
953         27 => "MONTH",
954         28 => "MOYR",
955         29 => "QYR",
956         30 => "WKYR",
957         31 => "PCT",
958         32 => "DOT",
959         33 => "CCA",
960         34 => "CCB",
961         35 => "CCC",
962         36 => "CCD",
963         37 => "CCE",
964         38 => "EDATE",
965         39 => "SDATE",
966         40 => "MTIME",
967         41 => "YMDHMS",
968         _ => return format!("<unknown format {type_}>").into(),
969     }
970     .into()
971 }
972
973 #[derive(Clone)]
974 pub struct MissingValues<S>
975 where
976     S: Debug,
977 {
978     /// Individual missing values, up to 3 of them.
979     pub values: Vec<Value<S>>,
980
981     /// Optional range of missing values.
982     pub range: Option<(Value<S>, Value<S>)>,
983 }
984
985 impl<S> Debug for MissingValues<S>
986 where
987     S: Debug,
988 {
989     fn fmt(&self, f: &mut Formatter) -> FmtResult {
990         for (i, value) in self.values.iter().enumerate() {
991             if i > 0 {
992                 write!(f, ", ")?;
993             }
994             write!(f, "{value:?}")?;
995         }
996
997         if let Some((low, high)) = &self.range {
998             if !self.values.is_empty() {
999                 write!(f, ", ")?;
1000             }
1001             write!(f, "{low:?} THRU {high:?}")?;
1002         }
1003
1004         if self.is_empty() {
1005             write!(f, "none")?;
1006         }
1007
1008         Ok(())
1009     }
1010 }
1011
1012 impl<S> MissingValues<S>
1013 where
1014     S: Debug,
1015 {
1016     fn is_empty(&self) -> bool {
1017         self.values.is_empty() && self.range.is_none()
1018     }
1019 }
1020
1021 impl MissingValues<RawStr<8>> {
1022     fn read<R: Read + Seek>(
1023         r: &mut R,
1024         offset: u64,
1025         width: i32,
1026         code: i32,
1027         endian: Endian,
1028     ) -> Result<Self, Error> {
1029         let (n_values, has_range) = match (width, code) {
1030             (_, 0..=3) => (code, false),
1031             (0, -2) => (0, true),
1032             (0, -3) => (1, true),
1033             (0, _) => return Err(Error::BadNumericMissingValueCode { offset, code }),
1034             (_, _) => return Err(Error::BadStringMissingValueCode { offset, code }),
1035         };
1036
1037         let var_type = VarType::from_width(width);
1038
1039         let mut values = Vec::new();
1040         for _ in 0..n_values {
1041             values.push(RawValue::read(r, var_type, endian)?);
1042         }
1043         let range = if has_range {
1044             let low = RawValue::read(r, var_type, endian)?;
1045             let high = RawValue::read(r, var_type, endian)?;
1046             Some((low, high))
1047         } else {
1048             None
1049         };
1050         Ok(Self { values, range })
1051     }
1052     fn decode<'a>(&'a self, decoder: &Decoder) -> MissingValues<String> {
1053         MissingValues {
1054             values: self
1055                 .values
1056                 .iter()
1057                 .map(|value| value.decode(decoder))
1058                 .collect(),
1059             range: self
1060                 .range
1061                 .as_ref()
1062                 .map(|(low, high)| (low.decode(decoder), high.decode(decoder))),
1063         }
1064     }
1065 }
1066
1067 #[derive(Clone)]
1068 pub struct VariableRecord<S, V>
1069 where
1070     S: Debug,
1071     V: Debug,
1072 {
1073     /// Range of offsets in file.
1074     pub offsets: Range<u64>,
1075
1076     /// Variable width, in the range -1..=255.
1077     pub width: i32,
1078
1079     /// Variable name, padded on the right with spaces.
1080     pub name: S,
1081
1082     /// Print format.
1083     pub print_format: Spec,
1084
1085     /// Write format.
1086     pub write_format: Spec,
1087
1088     /// Missing values.
1089     pub missing_values: MissingValues<V>,
1090
1091     /// Optional variable label.
1092     pub label: Option<S>,
1093 }
1094
1095 impl<S, V> Debug for VariableRecord<S, V>
1096 where
1097     S: Debug,
1098     V: Debug,
1099 {
1100     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1101         writeln!(
1102             f,
1103             "Width: {} ({})",
1104             self.width,
1105             match self.width.cmp(&0) {
1106                 Ordering::Greater => "string",
1107                 Ordering::Equal => "numeric",
1108                 Ordering::Less => "long string continuation record",
1109             }
1110         )?;
1111         writeln!(f, "Print format: {:?}", self.print_format)?;
1112         writeln!(f, "Write format: {:?}", self.write_format)?;
1113         writeln!(f, "Name: {:?}", &self.name)?;
1114         writeln!(f, "Variable label: {:?}", self.label)?;
1115         writeln!(f, "Missing values: {:?}", self.missing_values)
1116     }
1117 }
1118
1119 impl VariableRecord<RawString, RawStr<8>> {
1120     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1121         let start_offset = r.stream_position()?;
1122         let width: i32 = endian.parse(read_bytes(r)?);
1123         let code_offset = r.stream_position()?;
1124         let has_variable_label: u32 = endian.parse(read_bytes(r)?);
1125         let missing_value_code: i32 = endian.parse(read_bytes(r)?);
1126         let print_format = Spec(endian.parse(read_bytes(r)?));
1127         let write_format = Spec(endian.parse(read_bytes(r)?));
1128         let name = RawString(read_vec(r, 8)?);
1129
1130         let label = match has_variable_label {
1131             0 => None,
1132             1 => {
1133                 let len: u32 = endian.parse(read_bytes(r)?);
1134                 let read_len = len.min(65535) as usize;
1135                 let label = RawString(read_vec(r, read_len)?);
1136
1137                 let padding_bytes = Integer::next_multiple_of(&len, &4) - len;
1138                 let _ = read_vec(r, padding_bytes as usize)?;
1139
1140                 Some(label)
1141             }
1142             _ => {
1143                 return Err(Error::BadVariableLabelCode {
1144                     start_offset,
1145                     code_offset,
1146                     code: has_variable_label,
1147                 })
1148             }
1149         };
1150
1151         let missing_values =
1152             MissingValues::read(r, start_offset, width, missing_value_code, endian)?;
1153
1154         let end_offset = r.stream_position()?;
1155
1156         Ok(Record::Variable(VariableRecord {
1157             offsets: start_offset..end_offset,
1158             width,
1159             name,
1160             print_format,
1161             write_format,
1162             missing_values,
1163             label,
1164         }))
1165     }
1166
1167     fn decode<'a>(&'a self, decoder: &Decoder) -> VariableRecord<Cow<'a, str>, String> {
1168         VariableRecord {
1169             offsets: self.offsets.clone(),
1170             width: self.width,
1171             name: decoder.decode(&self.name),
1172             print_format: self.print_format,
1173             write_format: self.write_format,
1174             missing_values: self.missing_values.decode(decoder),
1175             label: self.label.as_ref().map(|label| decoder.decode(label)),
1176         }
1177     }
1178 }
1179
1180 #[derive(Copy, Clone)]
1181 pub struct UntypedValue(pub [u8; 8]);
1182
1183 impl Debug for UntypedValue {
1184     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1185         let little: f64 = Endian::Little.parse(self.0);
1186         let little = format!("{:?}", little);
1187         let big: f64 = Endian::Big.parse(self.0);
1188         let big = format!("{:?}", big);
1189         let number = if little.len() <= big.len() {
1190             little
1191         } else {
1192             big
1193         };
1194         write!(f, "{number}")?;
1195
1196         let string = default_decode(&self.0);
1197         let string = string
1198             .split(|c: char| c == '\0' || c.is_control())
1199             .next()
1200             .unwrap();
1201         write!(f, "{string:?}")?;
1202         Ok(())
1203     }
1204 }
1205
1206 #[derive(Clone)]
1207 pub struct RawString(pub Vec<u8>);
1208
1209 impl From<Vec<u8>> for RawString {
1210     fn from(source: Vec<u8>) -> Self {
1211         Self(source)
1212     }
1213 }
1214
1215 impl From<&[u8]> for RawString {
1216     fn from(source: &[u8]) -> Self {
1217         Self(source.into())
1218     }
1219 }
1220
1221 impl Debug for RawString {
1222     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1223         write!(f, "{:?}", default_decode(self.0.as_slice()))
1224     }
1225 }
1226
1227 #[derive(Copy, Clone)]
1228 pub struct RawStr<const N: usize>(pub [u8; N]);
1229
1230 impl<const N: usize> From<[u8; N]> for RawStr<N> {
1231     fn from(source: [u8; N]) -> Self {
1232         Self(source)
1233     }
1234 }
1235
1236 impl<const N: usize> Debug for RawStr<N> {
1237     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1238         write!(f, "{:?}", default_decode(&self.0))
1239     }
1240 }
1241
1242 #[derive(Clone, Debug)]
1243 pub struct ValueLabel<V, S>
1244 where
1245     V: Debug,
1246     S: Debug,
1247 {
1248     pub value: Value<V>,
1249     pub label: S,
1250 }
1251
1252 #[derive(Clone)]
1253 pub struct ValueLabelRecord<V, S>
1254 where
1255     V: Debug,
1256     S: Debug,
1257 {
1258     /// Range of offsets in file.
1259     pub offsets: Range<u64>,
1260
1261     /// The labels.
1262     pub labels: Vec<ValueLabel<V, S>>,
1263
1264     /// The 1-based indexes of the variable indexes.
1265     pub dict_indexes: Vec<u32>,
1266
1267     /// The types of the variables.
1268     pub var_type: VarType,
1269 }
1270
1271 impl<V, S> Debug for ValueLabelRecord<V, S>
1272 where
1273     V: Debug,
1274     S: Debug,
1275 {
1276     fn fmt(&self, f: &mut Formatter) -> FmtResult {
1277         writeln!(f, "labels: ")?;
1278         for label in self.labels.iter() {
1279             writeln!(f, "{label:?}")?;
1280         }
1281         write!(f, "apply to {} variables", self.var_type)?;
1282         for dict_index in self.dict_indexes.iter() {
1283             write!(f, " #{dict_index}")?;
1284         }
1285         Ok(())
1286     }
1287 }
1288
1289 impl<V, S> Header for ValueLabelRecord<V, S>
1290 where
1291     V: Debug,
1292     S: Debug,
1293 {
1294     fn offsets(&self) -> Range<u64> {
1295         self.offsets.clone()
1296     }
1297 }
1298
1299 impl<V, S> ValueLabelRecord<V, S>
1300 where
1301     V: Debug,
1302     S: Debug,
1303 {
1304     /// Maximum number of value labels in a record.
1305     pub const MAX_LABELS: u32 = u32::MAX / 8;
1306
1307     /// Maximum number of variable indexes in a record.
1308     pub const MAX_INDEXES: u32 = u32::MAX / 8;
1309 }
1310
1311 impl ValueLabelRecord<RawStr<8>, RawString> {
1312     fn read<R: Read + Seek>(
1313         r: &mut R,
1314         endian: Endian,
1315         var_types: &[VarType],
1316         warn: &Box<dyn Fn(Error)>,
1317     ) -> Result<Option<Record>, Error> {
1318         let label_offset = r.stream_position()?;
1319         let n: u32 = endian.parse(read_bytes(r)?);
1320         if n > Self::MAX_LABELS {
1321             return Err(Error::BadNumberOfValueLabels {
1322                 offset: label_offset,
1323                 n,
1324                 max: Self::MAX_LABELS,
1325             });
1326         }
1327
1328         let mut labels = Vec::new();
1329         for _ in 0..n {
1330             let value = UntypedValue(read_bytes(r)?);
1331             let label_len: u8 = endian.parse(read_bytes(r)?);
1332             let label_len = label_len as usize;
1333             let padded_len = Integer::next_multiple_of(&(label_len + 1), &8);
1334
1335             let mut label = read_vec(r, padded_len - 1)?;
1336             label.truncate(label_len);
1337             labels.push((value, RawString(label)));
1338         }
1339
1340         let index_offset = r.stream_position()?;
1341         let rec_type: u32 = endian.parse(read_bytes(r)?);
1342         if rec_type != 4 {
1343             return Err(Error::ExpectedVarIndexRecord {
1344                 offset: index_offset,
1345                 rec_type,
1346             });
1347         }
1348
1349         let n: u32 = endian.parse(read_bytes(r)?);
1350         if n > Self::MAX_INDEXES {
1351             return Err(Error::TooManyVarIndexes {
1352                 offset: index_offset,
1353                 n,
1354                 max: Self::MAX_INDEXES,
1355             });
1356         }
1357
1358         let index_offset = r.stream_position()?;
1359         let mut dict_indexes = Vec::with_capacity(n as usize);
1360         let mut invalid_indexes = Vec::new();
1361         for _ in 0..n {
1362             let index: u32 = endian.parse(read_bytes(r)?);
1363             if index == 0 || index as usize > var_types.len() {
1364                 dict_indexes.push(index);
1365             } else {
1366                 invalid_indexes.push(index);
1367             }
1368         }
1369         if !invalid_indexes.is_empty() {
1370             warn(Error::InvalidVarIndexes {
1371                 offset: index_offset,
1372                 max: var_types.len(),
1373                 invalid: invalid_indexes,
1374             });
1375         }
1376
1377         let Some(&first_index) = dict_indexes.first() else {
1378             warn(Error::NoVarIndexes {
1379                 offset: index_offset,
1380             });
1381             return Ok(None);
1382         };
1383         let var_type = var_types[first_index as usize - 1];
1384         let mut wrong_type_indexes = Vec::new();
1385         dict_indexes.retain(|&index| {
1386             if var_types[index as usize - 1] != var_type {
1387                 wrong_type_indexes.push(index);
1388                 false
1389             } else {
1390                 true
1391             }
1392         });
1393         if !wrong_type_indexes.is_empty() {
1394             warn(Error::MixedVarTypes {
1395                 offset: index_offset,
1396                 var_type,
1397                 wrong_types: wrong_type_indexes,
1398             });
1399         }
1400
1401         let labels = labels
1402             .into_iter()
1403             .map(|(value, label)| ValueLabel {
1404                 value: Value::from_raw(&value, var_type, endian),
1405                 label,
1406             })
1407             .collect();
1408
1409         let end_offset = r.stream_position()?;
1410         Ok(Some(Record::ValueLabel(ValueLabelRecord {
1411             offsets: label_offset..end_offset,
1412             labels,
1413             dict_indexes,
1414             var_type,
1415         })))
1416     }
1417 }
1418
1419 #[derive(Clone, Debug)]
1420 pub struct DocumentRecord<S>
1421 where
1422     S: Debug,
1423 {
1424     pub offsets: Range<u64>,
1425
1426     /// The document, as an array of 80-byte lines.
1427     pub lines: Vec<S>,
1428 }
1429
1430 pub type RawDocumentLine = RawStr<DOC_LINE_LEN>;
1431
1432 /// Length of a line in a document.  Document lines are fixed-length and
1433 /// padded on the right with spaces.
1434 pub const DOC_LINE_LEN: usize = 80;
1435
1436 impl DocumentRecord<RawDocumentLine> {
1437     /// Maximum number of lines we will accept in a document.  This is simply
1438     /// the maximum number that will fit in a 32-bit space.
1439     pub const MAX_LINES: usize = i32::MAX as usize / DOC_LINE_LEN;
1440
1441     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1442         let start_offset = r.stream_position()?;
1443         let n: u32 = endian.parse(read_bytes(r)?);
1444         let n = n as usize;
1445         if n > Self::MAX_LINES {
1446             Err(Error::BadDocumentLength {
1447                 offset: start_offset,
1448                 n,
1449                 max: Self::MAX_LINES,
1450             })
1451         } else {
1452             let mut lines = Vec::with_capacity(n);
1453             for _ in 0..n {
1454                 lines.push(RawStr(read_bytes(r)?));
1455             }
1456             let end_offset = r.stream_position()?;
1457             Ok(Record::Document(DocumentRecord {
1458                 offsets: start_offset..end_offset,
1459                 lines,
1460             }))
1461         }
1462     }
1463
1464     fn decode<'a>(&'a self, decoder: &Decoder) -> DocumentRecord<Cow<'a, str>> {
1465         DocumentRecord {
1466             offsets: self.offsets.clone(),
1467             lines: self.lines.iter().map(|s| decoder.decode_slice(&s.0)).collect(),
1468         }
1469     }
1470 }
1471
1472 impl<S> Header for DocumentRecord<S>
1473 where
1474     S: Debug,
1475 {
1476     fn offsets(&self) -> Range<u64> {
1477         self.offsets.clone()
1478     }
1479 }
1480
1481 trait ExtensionRecord {
1482     const SUBTYPE: u32;
1483     const SIZE: Option<u32>;
1484     const COUNT: Option<u32>;
1485     const NAME: &'static str;
1486     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error>;
1487 }
1488
1489 #[derive(Clone, Debug)]
1490 pub struct IntegerInfoRecord {
1491     pub offsets: Range<u64>,
1492     pub version: (i32, i32, i32),
1493     pub machine_code: i32,
1494     pub floating_point_rep: i32,
1495     pub compression_code: i32,
1496     pub endianness: i32,
1497     pub character_code: i32,
1498 }
1499
1500 impl ExtensionRecord for IntegerInfoRecord {
1501     const SUBTYPE: u32 = 3;
1502     const SIZE: Option<u32> = Some(4);
1503     const COUNT: Option<u32> = Some(8);
1504     const NAME: &'static str = "integer record";
1505
1506     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1507         ext.check_size::<Self>()?;
1508
1509         let mut input = &ext.data[..];
1510         let data: Vec<i32> = (0..8)
1511             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1512             .collect();
1513         Ok(Record::IntegerInfo(IntegerInfoRecord {
1514             offsets: ext.offsets.clone(),
1515             version: (data[0], data[1], data[2]),
1516             machine_code: data[3],
1517             floating_point_rep: data[4],
1518             compression_code: data[5],
1519             endianness: data[6],
1520             character_code: data[7],
1521         }))
1522     }
1523 }
1524
1525 #[derive(Clone, Debug)]
1526 pub struct FloatInfoRecord {
1527     pub sysmis: f64,
1528     pub highest: f64,
1529     pub lowest: f64,
1530 }
1531
1532 impl ExtensionRecord for FloatInfoRecord {
1533     const SUBTYPE: u32 = 4;
1534     const SIZE: Option<u32> = Some(8);
1535     const COUNT: Option<u32> = Some(3);
1536     const NAME: &'static str = "floating point record";
1537
1538     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1539         ext.check_size::<Self>()?;
1540
1541         let mut input = &ext.data[..];
1542         let data: Vec<f64> = (0..3)
1543             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1544             .collect();
1545         Ok(Record::FloatInfo(FloatInfoRecord {
1546             sysmis: data[0],
1547             highest: data[1],
1548             lowest: data[2],
1549         }))
1550     }
1551 }
1552
1553 #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
1554 pub enum CategoryLabels {
1555     VarLabels,
1556     CountedValues,
1557 }
1558
1559 #[derive(Clone, Debug)]
1560 pub enum MultipleResponseType {
1561     MultipleDichotomy {
1562         value: RawString,
1563         labels: CategoryLabels,
1564     },
1565     MultipleCategory,
1566 }
1567
1568 impl MultipleResponseType {
1569     fn parse(input: &[u8]) -> Result<(MultipleResponseType, &[u8]), Error> {
1570         let (mr_type, input) = match input.split_first() {
1571             Some((b'C', input)) => (MultipleResponseType::MultipleCategory, input),
1572             Some((b'D', input)) => {
1573                 let (value, input) = parse_counted_string(input)?;
1574                 (
1575                     MultipleResponseType::MultipleDichotomy {
1576                         value,
1577                         labels: CategoryLabels::VarLabels,
1578                     },
1579                     input,
1580                 )
1581             }
1582             Some((b'E', input)) => {
1583                 let (labels, input) = if let Some(rest) = input.strip_prefix(b" 1 ") {
1584                     (CategoryLabels::CountedValues, rest)
1585                 } else if let Some(rest) = input.strip_prefix(b" 11 ") {
1586                     (CategoryLabels::VarLabels, rest)
1587                 } else {
1588                     return Err(Error::TBD);
1589                 };
1590                 let (value, input) = parse_counted_string(input)?;
1591                 (
1592                     MultipleResponseType::MultipleDichotomy { value, labels },
1593                     input,
1594                 )
1595             }
1596             _ => return Err(Error::TBD),
1597         };
1598         Ok((mr_type, input))
1599     }
1600 }
1601
1602 #[derive(Clone, Debug)]
1603 pub struct MultipleResponseSet {
1604     pub name: RawString,
1605     pub label: RawString,
1606     pub mr_type: MultipleResponseType,
1607     pub short_names: Vec<RawString>,
1608 }
1609
1610 impl MultipleResponseSet {
1611     fn parse(input: &[u8]) -> Result<(MultipleResponseSet, &[u8]), Error> {
1612         let Some(equals) = input.iter().position(|&b| b == b'=') else {
1613             return Err(Error::TBD);
1614         };
1615         let (name, input) = input.split_at(equals);
1616         let (mr_type, input) = MultipleResponseType::parse(input)?;
1617         let Some(input) = input.strip_prefix(b" ") else {
1618             return Err(Error::TBD);
1619         };
1620         let (label, mut input) = parse_counted_string(input)?;
1621         let mut vars = Vec::new();
1622         while input.first() != Some(&b'\n') {
1623             match input.split_first() {
1624                 Some((b' ', rest)) => {
1625                     let Some(length) = rest.iter().position(|b| b" \n".contains(b)) else {
1626                         return Err(Error::TBD);
1627                     };
1628                     let (var, rest) = rest.split_at(length);
1629                     if !var.is_empty() {
1630                         vars.push(var.into());
1631                     }
1632                     input = rest;
1633                 }
1634                 _ => return Err(Error::TBD),
1635             }
1636         }
1637         while input.first() == Some(&b'\n') {
1638             input = &input[1..];
1639         }
1640         Ok((
1641             MultipleResponseSet {
1642                 name: name.into(),
1643                 label,
1644                 mr_type,
1645                 short_names: vars,
1646             },
1647             input,
1648         ))
1649     }
1650 }
1651
1652 #[derive(Clone, Debug)]
1653 pub struct MultipleResponseRecord(pub Vec<MultipleResponseSet>);
1654
1655 impl ExtensionRecord for MultipleResponseRecord {
1656     const SUBTYPE: u32 = 7;
1657     const SIZE: Option<u32> = Some(1);
1658     const COUNT: Option<u32> = None;
1659     const NAME: &'static str = "multiple response set record";
1660
1661     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
1662         ext.check_size::<Self>()?;
1663
1664         let mut input = &ext.data[..];
1665         let mut sets = Vec::new();
1666         while !input.is_empty() {
1667             let (set, rest) = MultipleResponseSet::parse(input)?;
1668             sets.push(set);
1669             input = rest;
1670         }
1671         Ok(Record::MultipleResponse(MultipleResponseRecord(sets)))
1672     }
1673 }
1674
1675 fn parse_counted_string(input: &[u8]) -> Result<(RawString, &[u8]), Error> {
1676     let Some(space) = input.iter().position(|&b| b == b' ') else {
1677         return Err(Error::TBD);
1678     };
1679     let Ok(length) = from_utf8(&input[..space]) else {
1680         return Err(Error::TBD);
1681     };
1682     let Ok(length): Result<usize, _> = length.parse() else {
1683         return Err(Error::TBD);
1684     };
1685
1686     let input = &input[space + 1..];
1687     if input.len() < length {
1688         return Err(Error::TBD);
1689     };
1690
1691     let (string, rest) = input.split_at(length);
1692     Ok((string.into(), rest))
1693 }
1694
1695 #[derive(Clone, Debug)]
1696 pub struct VarDisplayRecord(pub Vec<u32>);
1697
1698 impl ExtensionRecord for VarDisplayRecord {
1699     const SUBTYPE: u32 = 11;
1700     const SIZE: Option<u32> = Some(4);
1701     const COUNT: Option<u32> = None;
1702     const NAME: &'static str = "variable display record";
1703
1704     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1705         ext.check_size::<Self>()?;
1706
1707         let mut input = &ext.data[..];
1708         let display = (0..ext.count)
1709             .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1710             .collect();
1711         Ok(Record::VarDisplay(VarDisplayRecord(display)))
1712     }
1713 }
1714
1715 #[derive(Clone, Debug)]
1716 pub struct LongStringMissingValues {
1717     /// Variable name.
1718     pub var_name: RawString,
1719
1720     /// Missing values.
1721     pub missing_values: MissingValues<RawStr<8>>,
1722 }
1723
1724 #[derive(Clone, Debug)]
1725 pub struct LongStringMissingValueRecord(pub Vec<LongStringMissingValues>);
1726
1727 impl ExtensionRecord for LongStringMissingValueRecord {
1728     const SUBTYPE: u32 = 22;
1729     const SIZE: Option<u32> = Some(1);
1730     const COUNT: Option<u32> = None;
1731     const NAME: &'static str = "long string missing values record";
1732
1733     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1734         ext.check_size::<Self>()?;
1735
1736         let mut input = &ext.data[..];
1737         let mut missing_value_set = Vec::new();
1738         while !input.is_empty() {
1739             let var_name = read_string(&mut input, endian)?;
1740             let n_missing_values: u8 = endian.parse(read_bytes(&mut input)?);
1741             let value_len: u32 = endian.parse(read_bytes(&mut input)?);
1742             if value_len != 8 {
1743                 let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offsets.start;
1744                 return Err(Error::BadLongMissingValueLength {
1745                     record_offset: ext.offsets.start,
1746                     offset,
1747                     value_len,
1748                 });
1749             }
1750             let mut values = Vec::new();
1751             for i in 0..n_missing_values {
1752                 let value: [u8; 8] = read_bytes(&mut input)?;
1753                 let numeric_value: u64 = endian.parse(value);
1754                 let value = if i > 0 && numeric_value == 8 {
1755                     // Tolerate files written by old, buggy versions of PSPP
1756                     // where we believed that the value_length was repeated
1757                     // before each missing value.
1758                     read_bytes(&mut input)?
1759                 } else {
1760                     value
1761                 };
1762                 values.push(Value::String(RawStr(value)));
1763             }
1764             let missing_values = MissingValues {
1765                 values,
1766                 range: None,
1767             };
1768             missing_value_set.push(LongStringMissingValues {
1769                 var_name,
1770                 missing_values,
1771             });
1772         }
1773         Ok(Record::LongStringMissingValues(
1774             LongStringMissingValueRecord(missing_value_set),
1775         ))
1776     }
1777 }
1778
1779 #[derive(Clone, Debug)]
1780 pub struct EncodingRecord(pub String);
1781
1782 impl ExtensionRecord for EncodingRecord {
1783     const SUBTYPE: u32 = 20;
1784     const SIZE: Option<u32> = Some(1);
1785     const COUNT: Option<u32> = None;
1786     const NAME: &'static str = "encoding record";
1787
1788     fn parse(ext: &Extension, _endian: Endian) -> Result<Record, Error> {
1789         ext.check_size::<Self>()?;
1790
1791         Ok(Record::Encoding(EncodingRecord(
1792             String::from_utf8(ext.data.clone()).map_err(|_| Error::BadEncodingName {
1793                 offset: ext.offsets.start,
1794             })?,
1795         )))
1796     }
1797 }
1798
1799 #[derive(Copy, Clone, Debug)]
1800 pub struct NumberOfCasesRecord {
1801     /// Always observed as 1.
1802     pub one: u64,
1803
1804     /// Number of cases.
1805     pub n_cases: u64,
1806 }
1807
1808 impl ExtensionRecord for NumberOfCasesRecord {
1809     const SUBTYPE: u32 = 16;
1810     const SIZE: Option<u32> = Some(8);
1811     const COUNT: Option<u32> = Some(2);
1812     const NAME: &'static str = "extended number of cases record";
1813
1814     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
1815         ext.check_size::<Self>()?;
1816
1817         let mut input = &ext.data[..];
1818         let one = endian.parse(read_bytes(&mut input)?);
1819         let n_cases = endian.parse(read_bytes(&mut input)?);
1820
1821         Ok(Record::NumberOfCases(NumberOfCasesRecord { one, n_cases }))
1822     }
1823 }
1824
1825 #[derive(Clone, Debug)]
1826 pub struct TextRecord {
1827     pub offsets: Range<u64>,
1828
1829     /// The text content of the record.
1830     pub text: RawString,
1831 }
1832
1833 impl From<Extension> for TextRecord {
1834     fn from(source: Extension) -> Self {
1835         TextRecord {
1836             offsets: source.offsets,
1837             text: source.data.into(),
1838         }
1839     }
1840 }
1841
1842 #[derive(Clone, Debug)]
1843 pub struct VariableSet {
1844     pub name: String,
1845     pub vars: Vec<String>,
1846 }
1847
1848 impl VariableSet {
1849     fn parse(input: &str) -> Result<Self, Error> {
1850         let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
1851         let vars = input.split_ascii_whitespace().map(String::from).collect();
1852         Ok(VariableSet {
1853             name: name.into(),
1854             vars,
1855         })
1856     }
1857 }
1858
1859 #[derive(Clone, Debug)]
1860 pub struct VariableSetRecord {
1861     pub offsets: Range<u64>,
1862     pub sets: Vec<VariableSet>
1863 }
1864
1865 impl VariableSetRecord {
1866     fn decode<'a>(source: &TextRecord, decoder: &Decoder) -> VariableSetRecord {
1867         let mut sets = Vec::new();
1868         let input = decoder.decode(&source.text);
1869         for line in input.lines() {
1870             if let Some(set) = VariableSet::parse(line).warn_on_error(&decoder.warn) {
1871                 sets.push(set)
1872             }
1873         }
1874         VariableSetRecord { offsets: source.offsets.clone(), sets }
1875     }
1876 }
1877
1878 trait WarnOnError<T> {
1879     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T>;
1880 }
1881 impl<T> WarnOnError<T> for Result<T, Error> {
1882     fn warn_on_error<F: Fn(Error)>(self, warn: &F) -> Option<T> {
1883         match self {
1884             Ok(result) => Some(result),
1885             Err(error) => {
1886                 warn(error);
1887                 None
1888             }
1889         }
1890     }
1891 }
1892
1893 #[derive(Clone, Debug)]
1894 pub struct Extension {
1895     pub offsets: Range<u64>,
1896
1897     /// Record subtype.
1898     pub subtype: u32,
1899
1900     /// Size of each data element.
1901     pub size: u32,
1902
1903     /// Number of data elements.
1904     pub count: u32,
1905
1906     /// `size * count` bytes of data.
1907     pub data: Vec<u8>,
1908 }
1909
1910 impl Extension {
1911     fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
1912         if let Some(expected_size) = E::SIZE {
1913             if self.size != expected_size {
1914                 return Err(Error::BadRecordSize {
1915                     offset: self.offsets.start,
1916                     record: E::NAME.into(),
1917                     size: self.size,
1918                     expected_size,
1919                 });
1920             }
1921         }
1922         if let Some(expected_count) = E::COUNT {
1923             if self.count != expected_count {
1924                 return Err(Error::BadRecordCount {
1925                     offset: self.offsets.start,
1926                     record: E::NAME.into(),
1927                     count: self.count,
1928                     expected_count,
1929                 });
1930             }
1931         }
1932         Ok(())
1933     }
1934
1935     fn read<R: Read + Seek>(
1936         r: &mut R,
1937         endian: Endian,
1938         warn: &Box<dyn Fn(Error)>,
1939     ) -> Result<Option<Record>, Error> {
1940         let subtype = endian.parse(read_bytes(r)?);
1941         let header_offset = r.stream_position()?;
1942         let size: u32 = endian.parse(read_bytes(r)?);
1943         let count = endian.parse(read_bytes(r)?);
1944         let Some(product) = size.checked_mul(count) else {
1945             return Err(Error::ExtensionRecordTooLarge {
1946                 offset: header_offset,
1947                 subtype,
1948                 size,
1949                 count,
1950             });
1951         };
1952         let start_offset = r.stream_position()?;
1953         let data = read_vec(r, product as usize)?;
1954         let end_offset = start_offset + product as u64;
1955         let extension = Extension {
1956             offsets: start_offset..end_offset,
1957             subtype,
1958             size,
1959             count,
1960             data,
1961         };
1962         let result = match subtype {
1963             IntegerInfoRecord::SUBTYPE => IntegerInfoRecord::parse(&extension, endian),
1964             FloatInfoRecord::SUBTYPE => FloatInfoRecord::parse(&extension, endian),
1965             VarDisplayRecord::SUBTYPE => VarDisplayRecord::parse(&extension, endian),
1966             MultipleResponseRecord::SUBTYPE | 19 => {
1967                 MultipleResponseRecord::parse(&extension, endian)
1968             }
1969             LongStringValueLabelRecord::SUBTYPE => {
1970                 LongStringValueLabelRecord::parse(&extension, endian)
1971             }
1972             EncodingRecord::SUBTYPE => EncodingRecord::parse(&extension, endian),
1973             NumberOfCasesRecord::SUBTYPE => NumberOfCasesRecord::parse(&extension, endian),
1974             5 => Ok(Record::VariableSets(extension.into())),
1975             10 => Ok(Record::ProductInfo(extension.into())),
1976             13 => Ok(Record::LongNames(extension.into())),
1977             14 => Ok(Record::VeryLongStrings(extension.into())),
1978             17 => Ok(Record::FileAttributes(extension.into())),
1979             18 => Ok(Record::VariableAttributes(extension.into())),
1980             _ => Ok(Record::OtherExtension(extension)),
1981         };
1982         match result {
1983             Ok(result) => Ok(Some(result)),
1984             Err(error) => {
1985                 warn(error);
1986                 Ok(None)
1987             }
1988         }
1989     }
1990 }
1991
1992 #[derive(Clone, Debug)]
1993 pub struct ZHeader {
1994     /// File offset to the start of the record.
1995     pub offset: u64,
1996
1997     /// File offset to the ZLIB data header.
1998     pub zheader_offset: u64,
1999
2000     /// File offset to the ZLIB trailer.
2001     pub ztrailer_offset: u64,
2002
2003     /// Length of the ZLIB trailer in bytes.
2004     pub ztrailer_len: u64,
2005 }
2006
2007 impl ZHeader {
2008     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
2009         let offset = r.stream_position()?;
2010         let zheader_offset: u64 = endian.parse(read_bytes(r)?);
2011         let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
2012         let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
2013
2014         Ok(ZHeader {
2015             offset,
2016             zheader_offset,
2017             ztrailer_offset,
2018             ztrailer_len,
2019         })
2020     }
2021 }
2022
2023 #[derive(Clone, Debug)]
2024 pub struct ZTrailer {
2025     /// File offset to the start of the record.
2026     pub offset: u64,
2027
2028     /// Compression bias as a negative integer, e.g. -100.
2029     pub int_bias: i64,
2030
2031     /// Always observed as zero.
2032     pub zero: u64,
2033
2034     /// Uncompressed size of each block, except possibly the last.  Only
2035     /// `0x3ff000` has been observed so far.
2036     pub block_size: u32,
2037
2038     /// Block descriptors, always `(ztrailer_len - 24) / 24)` of them.
2039     pub blocks: Vec<ZBlock>,
2040 }
2041
2042 #[derive(Clone, Debug)]
2043 pub struct ZBlock {
2044     /// Offset of block of data if simple compression were used.
2045     pub uncompressed_ofs: u64,
2046
2047     /// Actual offset within the file of the compressed data block.
2048     pub compressed_ofs: u64,
2049
2050     /// The number of bytes in this data block after decompression.  This is
2051     /// `block_size` in every data block but the last, which may be smaller.
2052     pub uncompressed_size: u32,
2053
2054     /// The number of bytes in this data block, as stored compressed in this
2055     /// file.
2056     pub compressed_size: u32,
2057 }
2058
2059 impl ZBlock {
2060     fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
2061         Ok(ZBlock {
2062             uncompressed_ofs: endian.parse(read_bytes(r)?),
2063             compressed_ofs: endian.parse(read_bytes(r)?),
2064             uncompressed_size: endian.parse(read_bytes(r)?),
2065             compressed_size: endian.parse(read_bytes(r)?),
2066         })
2067     }
2068 }
2069
2070 impl ZTrailer {
2071     fn read<R: Read + Seek>(
2072         reader: &mut R,
2073         endian: Endian,
2074         ztrailer_ofs: u64,
2075         ztrailer_len: u64,
2076     ) -> Result<Option<ZTrailer>, Error> {
2077         let start_offset = reader.stream_position()?;
2078         if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
2079             return Ok(None);
2080         }
2081         let int_bias = endian.parse(read_bytes(reader)?);
2082         let zero = endian.parse(read_bytes(reader)?);
2083         let block_size = endian.parse(read_bytes(reader)?);
2084         let n_blocks: u32 = endian.parse(read_bytes(reader)?);
2085         let expected_n_blocks = (ztrailer_len - 24) / 24;
2086         if n_blocks as u64 != expected_n_blocks {
2087             return Err(Error::BadZlibTrailerNBlocks {
2088                 offset: ztrailer_ofs,
2089                 n_blocks,
2090                 expected_n_blocks,
2091                 ztrailer_len,
2092             });
2093         }
2094         let blocks = (0..n_blocks)
2095             .map(|_| ZBlock::read(reader, endian))
2096             .collect::<Result<Vec<_>, _>>()?;
2097         reader.seek(SeekFrom::Start(start_offset))?;
2098         Ok(Some(ZTrailer {
2099             offset: ztrailer_ofs,
2100             int_bias,
2101             zero,
2102             block_size,
2103             blocks,
2104         }))
2105     }
2106 }
2107
2108 fn try_read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<Option<[u8; N]>, IoError> {
2109     let mut buf = [0; N];
2110     let n = r.read(&mut buf)?;
2111     if n > 0 {
2112         if n < N {
2113             r.read_exact(&mut buf[n..])?;
2114         }
2115         Ok(Some(buf))
2116     } else {
2117         Ok(None)
2118     }
2119 }
2120
2121 fn read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<[u8; N], IoError> {
2122     let mut buf = [0; N];
2123     r.read_exact(&mut buf)?;
2124     Ok(buf)
2125 }
2126
2127 fn read_vec<R: Read>(r: &mut R, n: usize) -> Result<Vec<u8>, IoError> {
2128     let mut vec = vec![0; n];
2129     r.read_exact(&mut vec)?;
2130     Ok(vec)
2131 }
2132
2133 fn read_string<R: Read>(r: &mut R, endian: Endian) -> Result<RawString, IoError> {
2134     let length: u32 = endian.parse(read_bytes(r)?);
2135     Ok(read_vec(r, length as usize)?.into())
2136 }
2137
2138 #[derive(Clone, Debug)]
2139 pub struct LongStringValueLabels {
2140     pub var_name: RawString,
2141     pub width: u32,
2142
2143     /// `(value, label)` pairs, where each value is `width` bytes.
2144     pub labels: Vec<(RawString, RawString)>,
2145 }
2146
2147 #[derive(Clone, Debug)]
2148 pub struct LongStringValueLabelRecord(pub Vec<LongStringValueLabels>);
2149
2150 impl ExtensionRecord for LongStringValueLabelRecord {
2151     const SUBTYPE: u32 = 21;
2152     const SIZE: Option<u32> = Some(1);
2153     const COUNT: Option<u32> = None;
2154     const NAME: &'static str = "long string value labels record";
2155
2156     fn parse(ext: &Extension, endian: Endian) -> Result<Record, Error> {
2157         ext.check_size::<Self>()?;
2158
2159         let mut input = &ext.data[..];
2160         let mut label_set = Vec::new();
2161         while !input.is_empty() {
2162             let var_name = read_string(&mut input, endian)?;
2163             let width: u32 = endian.parse(read_bytes(&mut input)?);
2164             let n_labels: u32 = endian.parse(read_bytes(&mut input)?);
2165             let mut labels = Vec::new();
2166             for _ in 0..n_labels {
2167                 let value = read_string(&mut input, endian)?;
2168                 let label = read_string(&mut input, endian)?;
2169                 labels.push((value, label));
2170             }
2171             label_set.push(LongStringValueLabels {
2172                 var_name,
2173                 width,
2174                 labels,
2175             })
2176         }
2177         Ok(Record::LongStringValueLabels(LongStringValueLabelRecord(
2178             label_set,
2179         )))
2180     }
2181 }