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