1 use crate::endian::{Endian, Parse, ToBytes};
4 use flate2::read::ZlibDecoder;
7 use std::fmt::{Debug, Formatter, Result as FmtResult};
8 use std::str::from_utf8;
10 collections::VecDeque,
11 io::{Error as IoError, Read, Seek, SeekFrom},
15 use self::state::State;
17 #[derive(Copy, Clone, Debug)]
18 pub enum Compression {
23 #[derive(Clone, Debug)]
28 ValueLabel(ValueLabel),
29 VarIndexes(VarIndexes),
30 IntegerInfo(IntegerInfo),
32 VariableSets(UnencodedString),
33 VarDisplay(VarDisplayRecord),
34 MultipleResponse(MultipleResponseRecord),
35 LongStringValueLabels(LongStringValueLabelRecord),
36 Encoding(EncodingRecord),
37 NumberOfCases(NumberOfCasesRecord),
38 ProductInfo(UnencodedString),
39 LongNames(UnencodedString),
40 LongStrings(UnencodedString),
41 FileAttributes(UnencodedString),
42 VariableAttributes(UnencodedString),
43 TextExtension(TextExtension),
52 fn read<R: Read + Seek>(reader: &mut R, endian: Endian) -> Result<Record, Error> {
53 let rec_type: u32 = endian.parse(read_bytes(reader)?);
55 2 => Ok(Record::Variable(Variable::read(reader, endian)?)),
56 3 => Ok(Record::ValueLabel(ValueLabel::read(reader, endian)?)),
57 4 => Ok(Record::VarIndexes(VarIndexes::read(reader, endian)?)),
58 6 => Ok(Record::Document(Document::read(reader, endian)?)),
59 7 => Ok(Extension::read(reader, endian)?),
60 999 => Ok(Record::EndOfHeaders(endian.parse(read_bytes(reader)?))),
61 _ => Err(Error::BadRecordType {
62 offset: reader.stream_position()?,
69 pub struct FallbackEncoding<'a>(&'a [u8]);
71 fn fallback_encode<'a>(s: &'a [u8]) -> Cow<'a, str> {
72 if let Ok(s) = from_utf8(s) {
77 .map(|c| char::from(*c))
83 impl<'a> Debug for FallbackEncoding<'a> {
84 fn fmt(&self, f: &mut Formatter) -> FmtResult {
85 if let Ok(s) = from_utf8(self.0) {
92 .map(|c| char::from(*c).escape_default())
106 /// Eye-catcher string, product name, in the file's encoding. Padded
107 /// on the right with spaces.
108 pub eye_catcher: [u8; 60],
110 /// Layout code, normally either 2 or 3.
111 pub layout_code: u32,
113 /// Number of variable positions, or `None` if the value in the file is
114 /// questionably trustworthy.
115 pub nominal_case_size: Option<u32>,
117 /// Compression type, if any,
118 pub compression: Option<Compression>,
120 /// 0-based variable index of the weight variable, or `None` if the file is
122 pub weight_index: Option<u32>,
124 /// Claimed number of cases, if known.
125 pub n_cases: Option<u32>,
127 /// Compression bias, usually 100.0.
130 /// `dd mmm yy` in the file's encoding.
131 pub creation_date: [u8; 9],
133 /// `HH:MM:SS` in the file's encoding.
134 pub creation_time: [u8; 8],
136 /// File label, in the file's encoding. Padded on the right with spaces.
137 pub file_label: [u8; 64],
139 /// Endianness of the data in the file header.
144 fn debug_field<T: Debug>(&self, f: &mut Formatter, name: &str, value: T) -> FmtResult {
145 writeln!(f, "{name:>17}: {:?}", value)
149 impl Debug for Header {
150 fn fmt(&self, f: &mut Formatter) -> FmtResult {
151 writeln!(f, "File header record:")?;
152 self.debug_field(f, "Magic", self.magic)?;
153 self.debug_field(f, "Product name", FallbackEncoding(&self.eye_catcher))?;
154 self.debug_field(f, "Layout code", self.layout_code)?;
155 self.debug_field(f, "Nominal case size", self.nominal_case_size)?;
156 self.debug_field(f, "Compression", self.compression)?;
157 self.debug_field(f, "Weight index", self.weight_index)?;
158 self.debug_field(f, "Number of cases", self.n_cases)?;
159 self.debug_field(f, "Compression bias", self.bias)?;
160 self.debug_field(f, "Creation date", FallbackEncoding(&self.creation_date))?;
161 self.debug_field(f, "Creation time", FallbackEncoding(&self.creation_time))?;
162 self.debug_field(f, "File label", FallbackEncoding(&self.file_label))?;
163 self.debug_field(f, "Endianness", self.endian)
168 fn read<R: Read>(r: &mut R) -> Result<Header, Error> {
169 let magic: [u8; 4] = read_bytes(r)?;
170 let magic: Magic = magic.try_into().map_err(|_| Error::NotASystemFile)?;
172 let eye_catcher: [u8; 60] = read_bytes(r)?;
173 let layout_code: [u8; 4] = read_bytes(r)?;
174 let endian = Endian::identify_u32(2, layout_code)
175 .or_else(|| Endian::identify_u32(2, layout_code))
176 .ok_or_else(|| Error::NotASystemFile)?;
177 let layout_code = endian.parse(layout_code);
179 let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
180 let nominal_case_size =
181 (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
183 let compression_code: u32 = endian.parse(read_bytes(r)?);
184 let compression = match (magic, compression_code) {
185 (Magic::ZSAV, 2) => Some(Compression::ZLib),
186 (Magic::ZSAV, code) => return Err(Error::InvalidZsavCompression(code)),
188 (_, 1) => Some(Compression::Simple),
189 (_, code) => return Err(Error::InvalidSavCompression(code)),
192 let weight_index: u32 = endian.parse(read_bytes(r)?);
193 let weight_index = (weight_index > 0).then(|| weight_index - 1);
195 let n_cases: u32 = endian.parse(read_bytes(r)?);
196 let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
198 let bias: f64 = endian.parse(read_bytes(r)?);
200 let creation_date: [u8; 9] = read_bytes(r)?;
201 let creation_time: [u8; 8] = read_bytes(r)?;
202 let file_label: [u8; 64] = read_bytes(r)?;
203 let _: [u8; 3] = read_bytes(r)?;
222 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
223 pub struct Magic([u8; 4]);
226 /// Magic number for a regular system file.
227 pub const SAV: Magic = Magic(*b"$FL2");
229 /// Magic number for a system file that contains zlib-compressed data.
230 pub const ZSAV: Magic = Magic(*b"$FL3");
232 /// Magic number for an EBDIC-encoded system file. This is `$FL2` encoded
234 pub const EBCDIC: Magic = Magic([0x5b, 0xc6, 0xd3, 0xf2]);
237 impl Debug for Magic {
238 fn fmt(&self, f: &mut Formatter) -> FmtResult {
240 &Magic::SAV => "$FL2",
241 &Magic::ZSAV => "$FL3",
242 &Magic::EBCDIC => "($FL2 in EBCDIC)",
243 _ => return write!(f, "{:?}", self.0),
249 impl TryFrom<[u8; 4]> for Magic {
252 fn try_from(value: [u8; 4]) -> Result<Self, Self::Error> {
253 let magic = Magic(value);
255 Magic::SAV | Magic::ZSAV | Magic::EBCDIC => Ok(magic),
256 _ => Err(Error::BadMagic(value)),
261 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
268 fn from_width(width: i32) -> VarType {
270 0 => VarType::Number,
271 _ => VarType::String,
278 Compression, Error, Header, Record, Value, VarType, Variable, ZHeader, ZTrailer,
281 use crate::endian::Endian;
283 collections::VecDeque,
288 #[allow(clippy::type_complexity)]
289 fn read(self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error>;
292 struct Start<R: Read + Seek> {
296 pub fn new<R: Read + Seek + 'static>(reader: R) -> Box<dyn State> {
297 Box::new(Start { reader })
300 struct CommonState<R: Read + Seek> {
304 compression: Option<Compression>,
305 var_types: Vec<VarType>,
308 impl<R: Read + Seek + 'static> State for Start<R> {
309 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
310 let header = Header::read(&mut self.reader)?;
311 let next_state = Headers(CommonState {
313 endian: header.endian,
315 compression: header.compression,
316 var_types: Vec::new(),
318 Ok(Some((Record::Header(header), Box::new(next_state))))
322 struct Headers<R: Read + Seek>(CommonState<R>);
324 impl<R: Read + Seek + 'static> State for Headers<R> {
325 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
326 let record = Record::read(&mut self.0.reader, self.0.endian)?;
328 Record::Variable(Variable { width, .. }) => {
329 self.0.var_types.push(VarType::from_width(width));
331 Record::EndOfHeaders(_) => {
332 let next_state: Box<dyn State> = match self.0.compression {
333 None => Box::new(Data(self.0)),
334 Some(Compression::Simple) => Box::new(CompressedData::new(self.0)),
335 Some(Compression::ZLib) => Box::new(ZlibHeader(self.0)),
337 return Ok(Some((record, next_state)));
341 Ok(Some((record, self)))
345 struct ZlibHeader<R: Read + Seek>(CommonState<R>);
347 impl<R: Read + Seek + 'static> State for ZlibHeader<R> {
348 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
349 let zheader = ZHeader::read(&mut self.0.reader, self.0.endian)?;
350 Ok(Some((Record::ZHeader(zheader), self)))
354 struct ZlibTrailer<R: Read + Seek>(CommonState<R>, ZHeader);
356 impl<R: Read + Seek + 'static> State for ZlibTrailer<R> {
357 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
358 let retval = ZTrailer::read(
361 self.1.ztrailer_offset,
364 let next_state = Box::new(CompressedData::new(CommonState {
365 reader: ZlibDecodeMultiple::new(self.0.reader),
366 endian: self.0.endian,
368 compression: self.0.compression,
369 var_types: self.0.var_types,
372 None => next_state.read(),
373 Some(ztrailer) => Ok(Some((Record::ZTrailer(ztrailer), next_state))),
378 struct Data<R: Read + Seek>(CommonState<R>);
380 impl<R: Read + Seek + 'static> State for Data<R> {
381 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
382 match Value::read_case(&mut self.0.reader, &self.0.var_types, self.0.endian)? {
384 Some(values) => Ok(Some((Record::Case(values), self))),
389 struct CompressedData<R: Read + Seek> {
390 common: CommonState<R>,
394 impl<R: Read + Seek + 'static> CompressedData<R> {
395 fn new(common: CommonState<R>) -> CompressedData<R> {
398 codes: VecDeque::new(),
403 impl<R: Read + Seek + 'static> State for CompressedData<R> {
404 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
405 match Value::read_compressed_case(
406 &mut self.common.reader,
407 &self.common.var_types,
413 Some(values) => Ok(Some((Record::Case(values), self))),
419 #[derive(Copy, Clone)]
425 impl Debug for Value {
426 fn fmt(&self, f: &mut Formatter) -> FmtResult {
428 Value::Number(Some(number)) => write!(f, "{number:?}"),
429 Value::Number(None) => write!(f, "SYSMIS"),
430 Value::String(bytes) => write!(f, "{:?}", FallbackEncoding(bytes)),
436 fn read<R: Read>(r: &mut R, var_type: VarType, endian: Endian) -> Result<Value, IoError> {
437 Ok(Self::from_raw(var_type, read_bytes(r)?, endian))
440 pub fn from_raw(var_type: VarType, raw: [u8; 8], endian: Endian) -> Value {
442 VarType::String => Value::String(raw),
444 let number: f64 = endian.parse(raw);
445 Value::Number((number != -f64::MAX).then_some(number))
450 fn read_case<R: Read + Seek>(
452 var_types: &[VarType],
454 ) -> Result<Option<Vec<Value>>, Error> {
455 let case_start = reader.stream_position()?;
456 let mut values = Vec::with_capacity(var_types.len());
457 for (i, &var_type) in var_types.iter().enumerate() {
458 let Some(raw) = try_read_bytes(reader)? else {
462 let offset = reader.stream_position()?;
463 return Err(Error::EofInCase {
465 case_ofs: offset - case_start,
466 case_len: var_types.len() * 8,
470 values.push(Value::from_raw(var_type, raw, endian));
475 fn read_compressed_case<R: Read + Seek>(
477 var_types: &[VarType],
478 codes: &mut VecDeque<u8>,
481 ) -> Result<Option<Vec<Value>>, Error> {
482 let case_start = reader.stream_position()?;
483 let mut values = Vec::with_capacity(var_types.len());
484 for (i, &var_type) in var_types.iter().enumerate() {
486 let Some(code) = codes.pop_front() else {
487 let Some(new_codes): Option<[u8; 8]> = try_read_bytes(reader)? else {
491 let offset = reader.stream_position()?;
492 return Err(Error::EofInCompressedCase {
494 case_ofs: offset - case_start,
498 codes.extend(new_codes.into_iter());
503 1..=251 => match var_type {
504 VarType::Number => break Value::Number(Some(code as f64 - bias)),
506 break Value::String(endian.to_bytes(code as f64 - bias))
513 let offset = reader.stream_position()?;
514 return Err(Error::PartialCompressedCase {
516 case_ofs: offset - case_start,
520 253 => break Value::from_raw(var_type, read_bytes(reader)?, endian),
521 254 => match var_type {
522 VarType::String => break Value::String(*b" "), // XXX EBCDIC
524 return Err(Error::CompressedStringExpected {
526 case_ofs: reader.stream_position()? - case_start,
530 255 => match var_type {
531 VarType::Number => break Value::Number(None),
533 return Err(Error::CompressedNumberExpected {
535 case_ofs: reader.stream_position()? - case_start,
547 struct ZlibDecodeMultiple<R>
551 reader: Option<ZlibDecoder<R>>,
554 impl<R> ZlibDecodeMultiple<R>
558 fn new(reader: R) -> ZlibDecodeMultiple<R> {
560 reader: Some(ZlibDecoder::new(reader)),
565 impl<R> Read for ZlibDecodeMultiple<R>
569 fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
571 match self.reader.as_mut().unwrap().read(buf)? {
573 let inner = self.reader.take().unwrap().into_inner();
574 self.reader = Some(ZlibDecoder::new(inner));
582 impl<R> Seek for ZlibDecodeMultiple<R>
586 fn seek(&mut self, pos: SeekFrom) -> Result<u64, IoError> {
587 self.reader.as_mut().unwrap().get_mut().seek(pos)
592 state: Option<Box<dyn State>>,
596 pub fn new<R: Read + Seek + 'static>(reader: R) -> Result<Reader, Error> {
598 state: Some(state::new(reader)),
601 pub fn collect_headers(&mut self) -> Result<Vec<Record>, Error> {
602 let mut headers = Vec::new();
605 Record::EndOfHeaders(_) => break,
606 r => headers.push(r),
613 impl Iterator for Reader {
614 type Item = Result<Record, Error>;
616 fn next(&mut self) -> Option<Self::Item> {
617 match self.state.take()?.read() {
618 Ok(Some((record, next_state))) => {
619 self.state = Some(next_state);
623 Err(error) => Some(Err(error)),
628 impl FusedIterator for Reader {}
630 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
631 pub struct Format(pub u32);
633 impl Debug for Format {
634 fn fmt(&self, f: &mut Formatter) -> FmtResult {
635 let type_ = format_name(self.0 >> 16);
636 let w = (self.0 >> 8) & 0xff;
637 let d = self.0 & 0xff;
638 write!(f, "{:06x} ({type_}{w}.{d})", self.0)
642 fn format_name(type_: u32) -> &'static str {
686 pub struct MissingValues {
687 /// Individual missing values, up to 3 of them.
688 pub values: Vec<Value>,
690 /// Optional range of missing values.
691 pub range: Option<(Value, Value)>,
694 impl Debug for MissingValues {
695 fn fmt(&self, f: &mut Formatter) -> FmtResult {
696 for (i, value) in self.values.iter().enumerate() {
700 write!(f, "{value:?}")?;
703 if let Some((low, high)) = self.range {
704 if !self.values.is_empty() {
707 write!(f, "{low:?} THRU {high:?}")?;
719 fn is_empty(&self) -> bool {
720 self.values.is_empty() && self.range.is_none()
723 fn read<R: Read + Seek>(
729 ) -> Result<MissingValues, Error> {
730 let (n_values, has_range) = match (width, code) {
731 (_, 0..=3) => (code, false),
732 (0, -2) => (0, true),
733 (0, -3) => (1, true),
734 (0, _) => return Err(Error::BadNumericMissingValueCode { offset, code }),
735 (_, _) => return Err(Error::BadStringMissingValueCode { offset, code }),
738 let var_type = VarType::from_width(width);
740 let mut values = Vec::new();
741 for _ in 0..n_values {
742 values.push(Value::read(r, var_type, endian)?);
744 let range = if has_range {
745 let low = Value::read(r, var_type, endian)?;
746 let high = Value::read(r, var_type, endian)?;
751 Ok(MissingValues { values, range })
756 pub struct Variable {
757 /// Offset from the start of the file to the start of the record.
760 /// Variable width, in the range -1..=255.
763 /// Variable name, padded on the right with spaces.
767 pub print_format: u32,
770 pub write_format: u32,
773 pub missing_values: MissingValues,
775 /// Optional variable label.
776 pub label: Option<UnencodedString>,
779 impl Debug for Variable {
780 fn fmt(&self, f: &mut Formatter) -> FmtResult {
787 } else if self.width == 0 {
790 "long string continuation record"
793 writeln!(f, "Print format: {:?}", Format(self.print_format))?;
794 writeln!(f, "Write format: {:?}", Format(self.write_format))?;
795 writeln!(f, "Name: {:?}", FallbackEncoding(&self.name))?;
798 "Variable label: {:?}",
801 writeln!(f, "Missing values: {:?}", self.missing_values)
806 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Variable, Error> {
807 let offset = r.stream_position()?;
808 let width: i32 = endian.parse(read_bytes(r)?);
809 let has_variable_label: u32 = endian.parse(read_bytes(r)?);
810 let missing_value_code: i32 = endian.parse(read_bytes(r)?);
811 let print_format: u32 = endian.parse(read_bytes(r)?);
812 let write_format: u32 = endian.parse(read_bytes(r)?);
813 let name: [u8; 8] = read_bytes(r)?;
815 let label = match has_variable_label {
818 let len: u32 = endian.parse(read_bytes(r)?);
819 let read_len = len.min(65535) as usize;
820 let label = UnencodedString(read_vec(r, read_len)?);
822 let padding_bytes = Integer::next_multiple_of(&len, &4) - len;
823 let _ = read_vec(r, padding_bytes as usize)?;
828 return Err(Error::BadVariableLabelCode {
830 code: has_variable_label,
835 let missing_values = MissingValues::read(r, offset, width, missing_value_code, endian)?;
849 #[derive(Copy, Clone)]
850 pub struct UntypedValue(pub [u8; 8]);
852 impl Debug for UntypedValue {
853 fn fmt(&self, f: &mut Formatter) -> FmtResult {
854 let little: f64 = Endian::Little.parse(self.0);
855 let little = format!("{:?}", little);
856 let big: f64 = Endian::Big.parse(self.0);
857 let big = format!("{:?}", big);
858 let number = if little.len() <= big.len() { little } else { big };
859 write!(f, "{number}")?;
861 let string = fallback_encode(&self.0);
862 let string = string.split(|c: char| c == '\0' || c.is_control()).next().unwrap();
863 write!(f, "/\"{string}\"")?;
869 pub struct UnencodedString(Vec<u8>);
871 impl From<Vec<u8>> for UnencodedString {
872 fn from(source: Vec<u8>) -> Self {
877 impl From<&[u8]> for UnencodedString {
878 fn from(source: &[u8]) -> Self {
883 impl Debug for UnencodedString {
884 fn fmt(&self, f: &mut Formatter) -> FmtResult {
885 write!(f, "{:?}", FallbackEncoding(self.0.as_slice()))
890 pub struct ValueLabel {
891 /// Offset from the start of the file to the start of the record.
895 pub labels: Vec<(UntypedValue, UnencodedString)>,
898 impl Debug for ValueLabel {
899 fn fmt(&self, f: &mut Formatter) -> FmtResult {
900 for (value, label) in self.labels.iter() {
901 writeln!(f, "{value:?}: {label:?}")?;
908 /// Maximum number of value labels in a record.
909 pub const MAX: u32 = u32::MAX / 8;
911 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ValueLabel, Error> {
912 let offset = r.stream_position()?;
913 let n: u32 = endian.parse(read_bytes(r)?);
914 if n > ValueLabel::MAX {
915 return Err(Error::BadNumberOfValueLabels {
918 max: ValueLabel::MAX,
922 let mut labels = Vec::new();
924 let value = UntypedValue(read_bytes(r)?);
925 let label_len: u8 = endian.parse(read_bytes(r)?);
926 let label_len = label_len as usize;
927 let padded_len = Integer::next_multiple_of(&(label_len + 1), &8);
929 let mut label = read_vec(r, padded_len - 1)?;
930 label.truncate(label_len);
931 labels.push((value, UnencodedString(label)));
933 Ok(ValueLabel { offset, labels })
938 pub struct VarIndexes {
939 /// Offset from the start of the file to the start of the record.
942 /// The 0-based indexes of the variable indexes.
943 pub var_indexes: Vec<u32>,
946 impl Debug for VarIndexes {
947 fn fmt(&self, f: &mut Formatter) -> FmtResult {
948 write!(f, "apply to variables")?;
949 for var_index in self.var_indexes.iter() {
950 write!(f, " #{var_index}")?;
957 /// Maximum number of variable indexes in a record.
958 pub const MAX: u32 = u32::MAX / 8;
960 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<VarIndexes, Error> {
961 let offset = r.stream_position()?;
962 let n: u32 = endian.parse(read_bytes(r)?);
963 if n > VarIndexes::MAX {
964 return Err(Error::BadNumberOfVarIndexes {
967 max: VarIndexes::MAX,
970 let mut var_indexes = Vec::with_capacity(n as usize);
972 var_indexes.push(endian.parse(read_bytes(r)?));
982 #[derive(Clone, Debug)]
983 pub struct Document {
984 /// Offset from the start of the file to the start of the record.
987 /// The document, as an array of 80-byte lines.
988 pub lines: Vec<[u8; Document::LINE_LEN as usize]>,
992 /// Length of a line in a document. Document lines are fixed-length and
993 /// padded on the right with spaces.
994 pub const LINE_LEN: u32 = 80;
996 /// Maximum number of lines we will accept in a document. This is simply
997 /// the maximum number that will fit in a 32-bit space.
998 pub const MAX_LINES: u32 = i32::MAX as u32 / Self::LINE_LEN;
1000 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Document, Error> {
1001 let offset = r.stream_position()?;
1002 let n: u32 = endian.parse(read_bytes(r)?);
1004 0..=Self::MAX_LINES => Ok(Document {
1005 pos: r.stream_position()?,
1007 .map(|_| read_bytes(r))
1008 .collect::<Result<Vec<_>, _>>()?,
1010 _ => Err(Error::BadDocumentLength {
1013 max: Self::MAX_LINES,
1023 const NAME: &'static str;
1024 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error>;
1027 trait ExtensionRecord
1032 const SIZE: Option<u32>;
1033 const COUNT: Option<u32>;
1034 const NAME: &'static str;
1035 fn parse(ext: &Extension, endian: Endian, warn: impl Fn(Error)) -> Result<Self, Error>;
1038 #[derive(Clone, Debug)]
1039 pub struct IntegerInfo {
1040 pub version: (i32, i32, i32),
1041 pub machine_code: i32,
1042 pub floating_point_rep: i32,
1043 pub compression_code: i32,
1044 pub endianness: i32,
1045 pub character_code: i32,
1048 impl ExtensionRecord for IntegerInfo {
1049 const SUBTYPE: u32 = 3;
1050 const SIZE: Option<u32> = Some(4);
1051 const COUNT: Option<u32> = Some(8);
1052 const NAME: &'static str = "integer record";
1054 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1055 ext.check_size::<Self>()?;
1057 let mut input = &ext.data[..];
1058 let data: Vec<i32> = (0..8)
1059 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1062 version: (data[0], data[1], data[2]),
1063 machine_code: data[3],
1064 floating_point_rep: data[4],
1065 compression_code: data[5],
1066 endianness: data[6],
1067 character_code: data[7],
1072 #[derive(Clone, Debug)]
1073 pub struct FloatInfo {
1079 impl ExtensionRecord for FloatInfo {
1080 const SUBTYPE: u32 = 4;
1081 const SIZE: Option<u32> = Some(8);
1082 const COUNT: Option<u32> = Some(3);
1083 const NAME: &'static str = "floating point record";
1085 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1086 ext.check_size::<Self>()?;
1088 let mut input = &ext.data[..];
1089 let data: Vec<f64> = (0..3)
1090 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1100 #[derive(Clone, Debug)]
1101 pub enum CategoryLabels {
1105 #[derive(Clone, Debug)]
1106 pub enum MultipleResponseType {
1108 value: UnencodedString,
1109 labels: CategoryLabels,
1113 #[derive(Clone, Debug)]
1114 pub struct MultipleResponseSet {
1115 pub name: UnencodedString,
1116 pub label: UnencodedString,
1117 pub mr_type: MultipleResponseType,
1118 pub vars: Vec<UnencodedString>,
1121 impl MultipleResponseSet {
1122 fn parse(input: &[u8]) -> Result<(MultipleResponseSet, &[u8]), Error> {
1123 let Some(equals) = input.iter().position(|&b| b == b'=') else {
1124 return Err(Error::TBD);
1126 let (name, input) = input.split_at(equals);
1127 let (mr_type, input) = match input.get(0) {
1128 Some(b'C') => (MultipleResponseType::MultipleCategory, &input[1..]),
1130 let (value, input) = parse_counted_string(&input[1..])?;
1132 MultipleResponseType::MultipleDichotomy {
1133 value: value.into(),
1134 labels: CategoryLabels::VarLabels,
1140 let Some(b' ') = input.get(1) else {
1141 return Err(Error::TBD);
1143 let input = &input[2..];
1144 let (labels, input) = if let Some(rest) = input.strip_prefix(b" 1 ") {
1145 (CategoryLabels::CountedValues, rest)
1146 } else if let Some(rest) = input.strip_prefix(b" 11 ") {
1147 (CategoryLabels::VarLabels, rest)
1149 return Err(Error::TBD);
1151 let (value, input) = parse_counted_string(input)?;
1153 MultipleResponseType::MultipleDichotomy {
1154 value: value.into(),
1160 _ => return Err(Error::TBD),
1162 let Some(b' ') = input.get(0) else {
1163 return Err(Error::TBD);
1165 let (label, mut input) = parse_counted_string(&input[1..])?;
1166 let mut vars = Vec::new();
1167 while input.get(0) == Some(&b' ') {
1168 input = &input[1..];
1169 let Some(length) = input.iter().position(|b| b" \n".contains(b)) else {
1170 return Err(Error::TBD);
1173 vars.push(input[..length].into());
1175 input = &input[length..];
1177 if input.get(0) != Some(&b'\n') {
1178 return Err(Error::TBD);
1180 while input.get(0) == Some(&b'\n') {
1181 input = &input[1..];
1184 MultipleResponseSet {
1186 label: label.into(),
1195 #[derive(Clone, Debug)]
1196 pub struct MultipleResponseRecord(Vec<MultipleResponseSet>);
1198 impl ExtensionRecord for MultipleResponseRecord {
1199 const SUBTYPE: u32 = 7;
1200 const SIZE: Option<u32> = Some(1);
1201 const COUNT: Option<u32> = None;
1202 const NAME: &'static str = "multiple response set record";
1204 fn parse(ext: &Extension, _endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1205 ext.check_size::<Self>()?;
1207 let mut input = &ext.data[..];
1208 let mut sets = Vec::new();
1209 while !input.is_empty() {
1210 let (set, rest) = MultipleResponseSet::parse(input)?;
1214 Ok(MultipleResponseRecord(sets))
1218 fn parse_counted_string(input: &[u8]) -> Result<(UnencodedString, &[u8]), Error> {
1219 let Some(space) = input.iter().position(|&b| b == b' ') else {
1220 return Err(Error::TBD);
1222 let Ok(length) = from_utf8(&input[..space]) else {
1223 return Err(Error::TBD);
1225 let Ok(length): Result<usize, _> = length.parse() else {
1226 return Err(Error::TBD);
1229 let input = &input[space + 1..];
1230 if input.len() < length {
1231 return Err(Error::TBD);
1234 let (string, rest) = input.split_at(length);
1235 Ok((string.into(), rest))
1238 pub struct ExtraProductInfo(String);
1240 impl TextRecord for ExtraProductInfo {
1241 const NAME: &'static str = "extra product info";
1242 fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
1243 Ok(ExtraProductInfo(input.into()))
1247 #[derive(Clone, Debug)]
1248 pub struct VarDisplayRecord(Vec<u32>);
1250 impl ExtensionRecord for VarDisplayRecord {
1251 const SUBTYPE: u32 = 11;
1252 const SIZE: Option<u32> = Some(4);
1253 const COUNT: Option<u32> = None;
1254 const NAME: &'static str = "variable display record";
1256 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1257 ext.check_size::<Self>()?;
1259 let mut input = &ext.data[..];
1260 let display = (0..ext.count)
1261 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1263 Ok(VarDisplayRecord(display))
1267 pub struct VariableSet {
1269 pub vars: Vec<String>,
1273 fn parse(input: &str) -> Result<Self, Error> {
1274 let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
1275 let vars = input.split_ascii_whitespace().map(String::from).collect();
1283 pub struct VariableSetRecord(Vec<VariableSet>);
1285 impl TextRecord for VariableSetRecord {
1286 const NAME: &'static str = "variable set";
1287 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1288 let mut sets = Vec::new();
1289 for line in input.lines() {
1290 match VariableSet::parse(line) {
1291 Ok(set) => sets.push(set),
1292 Err(error) => warn(error),
1295 Ok(VariableSetRecord(sets))
1299 pub struct LongVariableName {
1300 pub short_name: String,
1301 pub long_name: String,
1304 pub struct LongVariableNameRecord(Vec<LongVariableName>);
1306 impl TextRecord for LongVariableNameRecord {
1307 const NAME: &'static str = "long variable names";
1308 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1309 let mut names = Vec::new();
1310 for pair in input.split('\t').filter(|s| !s.is_empty()) {
1311 if let Some((short_name, long_name)) = pair.split_once('=') {
1312 let name = LongVariableName {
1313 short_name: short_name.into(),
1314 long_name: long_name.into(),
1321 Ok(LongVariableNameRecord(names))
1325 pub struct VeryLongString {
1326 pub short_name: String,
1330 impl VeryLongString {
1331 fn parse(input: &str) -> Result<VeryLongString, Error> {
1332 let Some((short_name, length)) = input.split_once('=') else {
1333 return Err(Error::TBD);
1335 let length: usize = length.parse().map_err(|_| Error::TBD)?;
1337 short_name: short_name.into(),
1343 pub struct VeryLongStringRecord(Vec<VeryLongString>);
1345 impl TextRecord for VeryLongStringRecord {
1346 const NAME: &'static str = "very long strings";
1347 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1348 let mut very_long_strings = Vec::new();
1351 .map(|s| s.trim_end_matches('\t'))
1352 .filter(|s| !s.is_empty())
1354 match VeryLongString::parse(tuple) {
1355 Ok(vls) => very_long_strings.push(vls),
1356 Err(error) => warn(error),
1359 Ok(VeryLongStringRecord(very_long_strings))
1363 #[derive(Clone, Debug)]
1364 pub struct LongStringValueLabels {
1365 pub var_name: UnencodedString,
1368 /// `(value, label)` pairs, where each value is `width` bytes.
1369 pub labels: Vec<(UnencodedString, UnencodedString)>,
1372 #[derive(Clone, Debug)]
1373 pub struct LongStringValueLabelRecord(Vec<LongStringValueLabels>);
1375 impl ExtensionRecord for LongStringValueLabelRecord {
1376 const SUBTYPE: u32 = 21;
1377 const SIZE: Option<u32> = Some(1);
1378 const COUNT: Option<u32> = None;
1379 const NAME: &'static str = "long string value labels record";
1381 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1382 ext.check_size::<Self>()?;
1384 let mut input = &ext.data[..];
1385 let mut label_set = Vec::new();
1386 while !input.is_empty() {
1387 let var_name = read_string(&mut input, endian)?;
1388 let width: u32 = endian.parse(read_bytes(&mut input)?);
1389 let n_labels: u32 = endian.parse(read_bytes(&mut input)?);
1390 let mut labels = Vec::new();
1391 for _ in 0..n_labels {
1392 let value = read_string(&mut input, endian)?;
1393 let label = read_string(&mut input, endian)?;
1394 labels.push((value, label));
1396 label_set.push(LongStringValueLabels {
1402 Ok(LongStringValueLabelRecord(label_set))
1406 pub struct LongStringMissingValues {
1408 pub var_name: UnencodedString,
1411 pub missing_values: MissingValues,
1414 pub struct LongStringMissingValueSet(Vec<LongStringMissingValues>);
1416 impl ExtensionRecord for LongStringMissingValueSet {
1417 const SUBTYPE: u32 = 22;
1418 const SIZE: Option<u32> = Some(1);
1419 const COUNT: Option<u32> = None;
1420 const NAME: &'static str = "long string missing values record";
1422 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1423 ext.check_size::<Self>()?;
1425 let mut input = &ext.data[..];
1426 let mut missing_value_set = Vec::new();
1427 while !input.is_empty() {
1428 let var_name = read_string(&mut input, endian)?;
1429 let n_missing_values: u8 = endian.parse(read_bytes(&mut input)?);
1430 let value_len: u32 = endian.parse(read_bytes(&mut input)?);
1432 let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offset;
1433 return Err(Error::BadLongMissingValueLength {
1434 record_offset: ext.offset,
1439 let mut values = Vec::new();
1440 for i in 0..n_missing_values {
1441 let value: [u8; 8] = read_bytes(&mut input)?;
1442 let numeric_value: u64 = endian.parse(value);
1443 let value = if i > 0 && numeric_value == 8 {
1444 // Tolerate files written by old, buggy versions of PSPP
1445 // where we believed that the value_length was repeated
1446 // before each missing value.
1447 read_bytes(&mut input)?
1451 values.push(Value::String(value));
1453 let missing_values = MissingValues { values, range: None };
1454 missing_value_set.push(LongStringMissingValues {
1459 Ok(LongStringMissingValueSet(missing_value_set))
1463 #[derive(Clone, Debug)]
1464 pub struct EncodingRecord(pub String);
1466 impl ExtensionRecord for EncodingRecord {
1467 const SUBTYPE: u32 = 20;
1468 const SIZE: Option<u32> = Some(1);
1469 const COUNT: Option<u32> = None;
1470 const NAME: &'static str = "encoding record";
1472 fn parse(ext: &Extension, _endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1473 ext.check_size::<Self>()?;
1475 Ok(EncodingRecord(String::from_utf8(ext.data.clone()).map_err(
1476 |_| Error::BadEncodingName { offset: ext.offset },
1481 pub struct Attribute {
1483 pub values: Vec<String>,
1487 fn parse<'a>(input: &'a str, warn: &impl Fn(Error)) -> Result<(Attribute, &'a str), Error> {
1488 let Some((name, mut input)) = input.split_once('(') else {
1489 return Err(Error::TBD);
1491 let mut values = Vec::new();
1493 let Some((value, rest)) = input.split_once('\n') else {
1494 return Err(Error::TBD);
1496 if let Some(stripped) = value
1498 .and_then(|value| value.strip_suffix('\''))
1500 values.push(stripped.into());
1503 values.push(value.into());
1505 if let Some(rest) = rest.strip_prefix(')') {
1519 pub struct AttributeSet(pub Vec<Attribute>);
1524 sentinel: Option<char>,
1525 warn: &impl Fn(Error),
1526 ) -> Result<(AttributeSet, &'a str), Error> {
1527 let mut attributes = Vec::new();
1529 match input.chars().next() {
1530 None => break input,
1531 c if c == sentinel => break &input[1..],
1533 let (attribute, rest) = Attribute::parse(input, &warn)?;
1534 attributes.push(attribute);
1539 Ok((AttributeSet(attributes), rest))
1543 pub struct FileAttributeRecord(AttributeSet);
1545 impl TextRecord for FileAttributeRecord {
1546 const NAME: &'static str = "data file attributes";
1547 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1548 let (set, rest) = AttributeSet::parse(input, None, &warn)?;
1549 if !rest.is_empty() {
1552 Ok(FileAttributeRecord(set))
1556 pub struct VarAttributeSet {
1557 pub long_var_name: String,
1558 pub attributes: AttributeSet,
1561 impl VarAttributeSet {
1564 warn: &impl Fn(Error),
1565 ) -> Result<(VarAttributeSet, &'a str), Error> {
1566 let Some((long_var_name, rest)) = input.split_once(':') else {
1567 return Err(Error::TBD);
1569 let (attributes, rest) = AttributeSet::parse(rest, Some('/'), warn)?;
1572 long_var_name: long_var_name.into(),
1580 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
1582 impl TextRecord for VariableAttributeRecord {
1583 const NAME: &'static str = "variable attributes";
1584 fn parse(mut input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1585 let mut var_attribute_sets = Vec::new();
1586 while !input.is_empty() {
1587 match VarAttributeSet::parse(input, &warn) {
1588 Ok((var_attribute, rest)) => {
1589 var_attribute_sets.push(var_attribute);
1598 Ok(VariableAttributeRecord(var_attribute_sets))
1602 #[derive(Clone, Debug)]
1603 pub struct NumberOfCasesRecord {
1604 /// Always observed as 1.
1607 /// Number of cases.
1611 impl ExtensionRecord for NumberOfCasesRecord {
1612 const SUBTYPE: u32 = 16;
1613 const SIZE: Option<u32> = Some(8);
1614 const COUNT: Option<u32> = Some(2);
1615 const NAME: &'static str = "extended number of cases record";
1617 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1618 ext.check_size::<Self>()?;
1620 let mut input = &ext.data[..];
1621 let one = endian.parse(read_bytes(&mut input)?);
1622 let n_cases = endian.parse(read_bytes(&mut input)?);
1624 Ok(NumberOfCasesRecord { one, n_cases })
1628 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1629 pub enum TextExtensionSubtype {
1634 FileAttributes = 17,
1635 VariableAttributes = 18,
1638 #[derive(Clone, Debug)]
1639 pub struct TextExtension {
1640 pub subtype: TextExtensionSubtype,
1641 pub string: UnencodedString,
1644 #[derive(Clone, Debug)]
1645 pub struct Extension {
1646 /// Offset from the start of the file to the start of the record.
1652 /// Size of each data element.
1655 /// Number of data elements.
1658 /// `size * count` bytes of data.
1663 fn extension_record_size_requirements(extension: ExtensionType) -> (u32, u32) {
1665 /* Implemented record types. */
1666 ExtensionType::Integer => (4, 8),
1667 ExtensionType::Float => (8, 3),
1668 ExtensionType::VarSets => (1, 0),
1669 ExtensionType::Mrsets => (1, 0),
1670 ExtensionType::ProductInfo => (1, 0),
1671 ExtensionType::Display => (4, 0),
1672 ExtensionType::LongNames => (1, 0),
1673 ExtensionType::LongStrings => (1, 0),
1674 ExtensionType::Ncases => (8, 2),
1675 ExtensionType::FileAttrs => (1, 0),
1676 ExtensionType::VarAttrs => (1, 0),
1677 ExtensionType::Mrsets2 => (1, 0),
1678 ExtensionType::Encoding => (1, 0),
1679 ExtensionType::LongLabels => (1, 0),
1680 ExtensionType::LongMissing => (1, 0),
1682 /* Ignored record types. */
1683 ExtensionType::Date => (0, 0),
1684 ExtensionType::DataEntry => (0, 0),
1685 ExtensionType::Dataview => (0, 0),
1691 fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
1692 if let Some(expected_size) = E::SIZE {
1693 if self.size != expected_size {
1694 return Err(Error::BadRecordSize {
1695 offset: self.offset,
1696 record: E::NAME.into(),
1702 if let Some(expected_count) = E::COUNT {
1703 if self.count != expected_count {
1704 return Err(Error::BadRecordCount {
1705 offset: self.offset,
1706 record: E::NAME.into(),
1715 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1716 let subtype = endian.parse(read_bytes(r)?);
1717 let offset = r.stream_position()?;
1718 let size: u32 = endian.parse(read_bytes(r)?);
1719 let count = endian.parse(read_bytes(r)?);
1720 let Some(product) = size.checked_mul(count) else {
1721 return Err(Error::ExtensionRecordTooLarge {
1728 let offset = r.stream_position()?;
1729 let data = read_vec(r, product as usize)?;
1730 let extension = Extension {
1738 IntegerInfo::SUBTYPE => Ok(Record::IntegerInfo(IntegerInfo::parse(&extension, endian, |_| ())?)),
1739 FloatInfo::SUBTYPE => Ok(Record::FloatInfo(FloatInfo::parse(&extension, endian, |_| ())?)),
1740 VarDisplayRecord::SUBTYPE => Ok(Record::VarDisplay(VarDisplayRecord::parse(&extension, endian, |_| ())?)),
1741 MultipleResponseRecord::SUBTYPE | 19 => Ok(Record::MultipleResponse(MultipleResponseRecord::parse(&extension, endian, |_| ())?)),
1742 LongStringValueLabelRecord::SUBTYPE => Ok(Record::LongStringValueLabels(LongStringValueLabelRecord::parse(&extension, endian, |_| ())?)),
1743 EncodingRecord::SUBTYPE => Ok(Record::Encoding(EncodingRecord::parse(&extension, endian, |_| ())?)),
1744 NumberOfCasesRecord::SUBTYPE => Ok(Record::NumberOfCases(NumberOfCasesRecord::parse(&extension, endian, |_| ())?)),
1745 x if x == TextExtensionSubtype::VariableSets as u32 => Ok(Record::VariableSets(UnencodedString(extension.data))),
1746 x if x == TextExtensionSubtype::ProductInfo as u32 => Ok(Record::ProductInfo(UnencodedString(extension.data))),
1747 x if x == TextExtensionSubtype::LongNames as u32 => Ok(Record::LongNames(UnencodedString(extension.data))),
1748 x if x == TextExtensionSubtype::LongStrings as u32 => Ok(Record::LongStrings(UnencodedString(extension.data))),
1749 x if x == TextExtensionSubtype::FileAttributes as u32 => Ok(Record::FileAttributes(UnencodedString(extension.data))),
1750 x if x == TextExtensionSubtype::VariableAttributes as u32 => Ok(Record::VariableAttributes(UnencodedString(extension.data))),
1751 _ => Ok(Record::Extension(extension))
1756 #[derive(Clone, Debug)]
1757 pub struct ZHeader {
1758 /// File offset to the start of the record.
1761 /// File offset to the ZLIB data header.
1762 pub zheader_offset: u64,
1764 /// File offset to the ZLIB trailer.
1765 pub ztrailer_offset: u64,
1767 /// Length of the ZLIB trailer in bytes.
1768 pub ztrailer_len: u64,
1772 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
1773 let offset = r.stream_position()?;
1774 let zheader_offset: u64 = endian.parse(read_bytes(r)?);
1775 let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
1776 let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
1787 #[derive(Clone, Debug)]
1788 pub struct ZTrailer {
1789 /// File offset to the start of the record.
1792 /// Compression bias as a negative integer, e.g. -100.
1795 /// Always observed as zero.
1798 /// Uncompressed size of each block, except possibly the last. Only
1799 /// `0x3ff000` has been observed so far.
1800 pub block_size: u32,
1802 /// Block descriptors, always `(ztrailer_len - 24) / 24)` of them.
1803 pub blocks: Vec<ZBlock>,
1806 #[derive(Clone, Debug)]
1808 /// Offset of block of data if simple compression were used.
1809 pub uncompressed_ofs: u64,
1811 /// Actual offset within the file of the compressed data block.
1812 pub compressed_ofs: u64,
1814 /// The number of bytes in this data block after decompression. This is
1815 /// `block_size` in every data block but the last, which may be smaller.
1816 pub uncompressed_size: u32,
1818 /// The number of bytes in this data block, as stored compressed in this
1820 pub compressed_size: u32,
1824 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
1826 uncompressed_ofs: endian.parse(read_bytes(r)?),
1827 compressed_ofs: endian.parse(read_bytes(r)?),
1828 uncompressed_size: endian.parse(read_bytes(r)?),
1829 compressed_size: endian.parse(read_bytes(r)?),
1835 fn read<R: Read + Seek>(
1840 ) -> Result<Option<ZTrailer>, Error> {
1841 let start_offset = reader.stream_position()?;
1842 if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
1845 let int_bias = endian.parse(read_bytes(reader)?);
1846 let zero = endian.parse(read_bytes(reader)?);
1847 let block_size = endian.parse(read_bytes(reader)?);
1848 let n_blocks: u32 = endian.parse(read_bytes(reader)?);
1849 let expected_n_blocks = (ztrailer_len - 24) / 24;
1850 if n_blocks as u64 != expected_n_blocks {
1851 return Err(Error::BadZlibTrailerNBlocks {
1852 offset: ztrailer_ofs,
1858 let blocks = (0..n_blocks)
1859 .map(|_| ZBlock::read(reader, endian))
1860 .collect::<Result<Vec<_>, _>>()?;
1861 reader.seek(SeekFrom::Start(start_offset))?;
1863 offset: ztrailer_ofs,
1872 fn try_read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<Option<[u8; N]>, IoError> {
1873 let mut buf = [0; N];
1874 let n = r.read(&mut buf)?;
1877 r.read_exact(&mut buf[n..])?;
1885 fn read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<[u8; N], IoError> {
1886 let mut buf = [0; N];
1887 r.read_exact(&mut buf)?;
1891 fn read_vec<R: Read>(r: &mut R, n: usize) -> Result<Vec<u8>, IoError> {
1892 let mut vec = vec![0; n];
1893 r.read_exact(&mut vec)?;
1897 fn read_string<R: Read>(r: &mut R, endian: Endian) -> Result<UnencodedString, IoError> {
1898 let length: u32 = endian.parse(read_bytes(r)?);
1899 Ok(read_vec(r, length as usize)?.into())