1 use crate::endian::{Endian, Parse, ToBytes};
2 use crate::{CategoryLabels, Compression, Error};
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(Clone, Debug)]
21 ValueLabel(ValueLabel),
22 VarIndexes(VarIndexes),
24 IntegerInfo(IntegerInfo),
26 VariableSets(UnencodedString),
27 VarDisplay(VarDisplayRecord),
28 MultipleResponse(MultipleResponseRecord),
29 LongStringValueLabels(LongStringValueLabelRecord),
30 Encoding(EncodingRecord),
31 NumberOfCases(NumberOfCasesRecord),
32 ProductInfo(UnencodedString),
33 LongNames(UnencodedString),
34 LongStrings(UnencodedString),
35 FileAttributes(UnencodedString),
36 VariableAttributes(UnencodedString),
37 TextExtension(TextExtension),
38 OtherExtension(Extension),
46 fn read<R: Read + Seek>(reader: &mut R, endian: Endian) -> Result<Record, Error> {
47 let rec_type: u32 = endian.parse(read_bytes(reader)?);
49 2 => Ok(Record::Variable(Variable::read(reader, endian)?)),
50 3 => Ok(Record::ValueLabel(ValueLabel::read(reader, endian)?)),
51 4 => Ok(Record::VarIndexes(VarIndexes::read(reader, endian)?)),
52 6 => Ok(Record::Document(Document::read(reader, endian)?)),
53 7 => Ok(Extension::read(reader, endian)?),
54 999 => Ok(Record::EndOfHeaders(endian.parse(read_bytes(reader)?))),
55 _ => Err(Error::BadRecordType {
56 offset: reader.stream_position()?,
63 pub struct FallbackEncoding<'a>(&'a [u8]);
65 fn fallback_encode<'a>(s: &'a [u8]) -> Cow<'a, str> {
66 if let Ok(s) = from_utf8(s) {
69 let s: String = s.iter().map(|c| char::from(*c)).collect();
74 impl<'a> Debug for FallbackEncoding<'a> {
75 fn fmt(&self, f: &mut Formatter) -> FmtResult {
76 if let Ok(s) = from_utf8(self.0) {
83 .map(|c| char::from(*c).escape_default())
97 /// Eye-catcher string, product name, in the file's encoding. Padded
98 /// on the right with spaces.
99 pub eye_catcher: [u8; 60],
101 /// Layout code, normally either 2 or 3.
102 pub layout_code: u32,
104 /// Number of variable positions, or `None` if the value in the file is
105 /// questionably trustworthy.
106 pub nominal_case_size: Option<u32>,
108 /// Compression type, if any,
109 pub compression: Option<Compression>,
111 /// 0-based variable index of the weight variable, or `None` if the file is
113 pub weight_index: Option<u32>,
115 /// Claimed number of cases, if known.
116 pub n_cases: Option<u32>,
118 /// Compression bias, usually 100.0.
121 /// `dd mmm yy` in the file's encoding.
122 pub creation_date: [u8; 9],
124 /// `HH:MM:SS` in the file's encoding.
125 pub creation_time: [u8; 8],
127 /// File label, in the file's encoding. Padded on the right with spaces.
128 pub file_label: [u8; 64],
130 /// Endianness of the data in the file header.
135 fn debug_field<T: Debug>(&self, f: &mut Formatter, name: &str, value: T) -> FmtResult {
136 writeln!(f, "{name:>17}: {:?}", value)
140 impl Debug for Header {
141 fn fmt(&self, f: &mut Formatter) -> FmtResult {
142 writeln!(f, "File header record:")?;
143 self.debug_field(f, "Magic", self.magic)?;
144 self.debug_field(f, "Product name", FallbackEncoding(&self.eye_catcher))?;
145 self.debug_field(f, "Layout code", self.layout_code)?;
146 self.debug_field(f, "Nominal case size", self.nominal_case_size)?;
147 self.debug_field(f, "Compression", self.compression)?;
148 self.debug_field(f, "Weight index", self.weight_index)?;
149 self.debug_field(f, "Number of cases", self.n_cases)?;
150 self.debug_field(f, "Compression bias", self.bias)?;
151 self.debug_field(f, "Creation date", FallbackEncoding(&self.creation_date))?;
152 self.debug_field(f, "Creation time", FallbackEncoding(&self.creation_time))?;
153 self.debug_field(f, "File label", FallbackEncoding(&self.file_label))?;
154 self.debug_field(f, "Endianness", self.endian)
159 fn read<R: Read>(r: &mut R) -> Result<Header, Error> {
160 let magic: [u8; 4] = read_bytes(r)?;
161 let magic: Magic = magic.try_into().map_err(|_| Error::NotASystemFile)?;
163 let eye_catcher: [u8; 60] = read_bytes(r)?;
164 let layout_code: [u8; 4] = read_bytes(r)?;
165 let endian = Endian::identify_u32(2, layout_code)
166 .or_else(|| Endian::identify_u32(2, layout_code))
167 .ok_or_else(|| Error::NotASystemFile)?;
168 let layout_code = endian.parse(layout_code);
170 let nominal_case_size: u32 = endian.parse(read_bytes(r)?);
171 let nominal_case_size =
172 (nominal_case_size <= i32::MAX as u32 / 16).then_some(nominal_case_size);
174 let compression_code: u32 = endian.parse(read_bytes(r)?);
175 let compression = match (magic, compression_code) {
176 (Magic::ZSAV, 2) => Some(Compression::ZLib),
177 (Magic::ZSAV, code) => return Err(Error::InvalidZsavCompression(code)),
179 (_, 1) => Some(Compression::Simple),
180 (_, code) => return Err(Error::InvalidSavCompression(code)),
183 let weight_index: u32 = endian.parse(read_bytes(r)?);
184 let weight_index = (weight_index > 0).then(|| weight_index - 1);
186 let n_cases: u32 = endian.parse(read_bytes(r)?);
187 let n_cases = (n_cases < i32::MAX as u32 / 2).then_some(n_cases);
189 let bias: f64 = endian.parse(read_bytes(r)?);
191 let creation_date: [u8; 9] = read_bytes(r)?;
192 let creation_time: [u8; 8] = read_bytes(r)?;
193 let file_label: [u8; 64] = read_bytes(r)?;
194 let _: [u8; 3] = read_bytes(r)?;
213 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
214 pub struct Magic([u8; 4]);
217 /// Magic number for a regular system file.
218 pub const SAV: Magic = Magic(*b"$FL2");
220 /// Magic number for a system file that contains zlib-compressed data.
221 pub const ZSAV: Magic = Magic(*b"$FL3");
223 /// Magic number for an EBDIC-encoded system file. This is `$FL2` encoded
225 pub const EBCDIC: Magic = Magic([0x5b, 0xc6, 0xd3, 0xf2]);
228 impl Debug for Magic {
229 fn fmt(&self, f: &mut Formatter) -> FmtResult {
231 &Magic::SAV => "$FL2",
232 &Magic::ZSAV => "$FL3",
233 &Magic::EBCDIC => "($FL2 in EBCDIC)",
234 _ => return write!(f, "{:?}", self.0),
240 impl TryFrom<[u8; 4]> for Magic {
243 fn try_from(value: [u8; 4]) -> Result<Self, Self::Error> {
244 let magic = Magic(value);
246 Magic::SAV | Magic::ZSAV | Magic::EBCDIC => Ok(magic),
247 _ => Err(Error::BadMagic(value)),
252 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
259 fn from_width(width: i32) -> VarType {
261 0 => VarType::Number,
262 _ => VarType::String,
269 Compression, Error, Header, Record, Value, VarType, Variable, ZHeader, ZTrailer,
272 use crate::endian::Endian;
274 collections::VecDeque,
279 #[allow(clippy::type_complexity)]
280 fn read(self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error>;
283 struct Start<R: Read + Seek> {
287 pub fn new<R: Read + Seek + 'static>(reader: R) -> Box<dyn State> {
288 Box::new(Start { reader })
291 struct CommonState<R: Read + Seek> {
295 compression: Option<Compression>,
296 var_types: Vec<VarType>,
299 impl<R: Read + Seek + 'static> State for Start<R> {
300 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
301 let header = Header::read(&mut self.reader)?;
302 let next_state = Headers(CommonState {
304 endian: header.endian,
306 compression: header.compression,
307 var_types: Vec::new(),
309 Ok(Some((Record::Header(header), Box::new(next_state))))
313 struct Headers<R: Read + Seek>(CommonState<R>);
315 impl<R: Read + Seek + 'static> State for Headers<R> {
316 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
317 let record = Record::read(&mut self.0.reader, self.0.endian)?;
319 Record::Variable(Variable { width, .. }) => {
320 self.0.var_types.push(VarType::from_width(width));
322 Record::EndOfHeaders(_) => {
323 let next_state: Box<dyn State> = match self.0.compression {
324 None => Box::new(Data(self.0)),
325 Some(Compression::Simple) => Box::new(CompressedData::new(self.0)),
326 Some(Compression::ZLib) => Box::new(ZlibHeader(self.0)),
328 return Ok(Some((record, next_state)));
332 Ok(Some((record, self)))
336 struct ZlibHeader<R: Read + Seek>(CommonState<R>);
338 impl<R: Read + Seek + 'static> State for ZlibHeader<R> {
339 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
340 let zheader = ZHeader::read(&mut self.0.reader, self.0.endian)?;
341 Ok(Some((Record::ZHeader(zheader), self)))
345 struct ZlibTrailer<R: Read + Seek>(CommonState<R>, ZHeader);
347 impl<R: Read + Seek + 'static> State for ZlibTrailer<R> {
348 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
349 let retval = ZTrailer::read(
352 self.1.ztrailer_offset,
355 let next_state = Box::new(CompressedData::new(CommonState {
356 reader: ZlibDecodeMultiple::new(self.0.reader),
357 endian: self.0.endian,
359 compression: self.0.compression,
360 var_types: self.0.var_types,
363 None => next_state.read(),
364 Some(ztrailer) => Ok(Some((Record::ZTrailer(ztrailer), next_state))),
369 struct Data<R: Read + Seek>(CommonState<R>);
371 impl<R: Read + Seek + 'static> State for Data<R> {
372 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
373 match Value::read_case(&mut self.0.reader, &self.0.var_types, self.0.endian)? {
375 Some(values) => Ok(Some((Record::Case(values), self))),
380 struct CompressedData<R: Read + Seek> {
381 common: CommonState<R>,
385 impl<R: Read + Seek + 'static> CompressedData<R> {
386 fn new(common: CommonState<R>) -> CompressedData<R> {
389 codes: VecDeque::new(),
394 impl<R: Read + Seek + 'static> State for CompressedData<R> {
395 fn read(mut self: Box<Self>) -> Result<Option<(Record, Box<dyn State>)>, Error> {
396 match Value::read_compressed_case(
397 &mut self.common.reader,
398 &self.common.var_types,
404 Some(values) => Ok(Some((Record::Case(values), self))),
410 #[derive(Copy, Clone)]
416 impl Debug for Value {
417 fn fmt(&self, f: &mut Formatter) -> FmtResult {
419 Value::Number(Some(number)) => write!(f, "{number:?}"),
420 Value::Number(None) => write!(f, "SYSMIS"),
421 Value::String(bytes) => write!(f, "{:?}", FallbackEncoding(bytes)),
427 fn read<R: Read>(r: &mut R, var_type: VarType, endian: Endian) -> Result<Value, IoError> {
428 Ok(Self::from_raw(var_type, read_bytes(r)?, endian))
431 pub fn from_raw(var_type: VarType, raw: [u8; 8], endian: Endian) -> Value {
433 VarType::String => Value::String(raw),
435 let number: f64 = endian.parse(raw);
436 Value::Number((number != -f64::MAX).then_some(number))
441 fn read_case<R: Read + Seek>(
443 var_types: &[VarType],
445 ) -> Result<Option<Vec<Value>>, Error> {
446 let case_start = reader.stream_position()?;
447 let mut values = Vec::with_capacity(var_types.len());
448 for (i, &var_type) in var_types.iter().enumerate() {
449 let Some(raw) = try_read_bytes(reader)? else {
453 let offset = reader.stream_position()?;
454 return Err(Error::EofInCase {
456 case_ofs: offset - case_start,
457 case_len: var_types.len() * 8,
461 values.push(Value::from_raw(var_type, raw, endian));
466 fn read_compressed_case<R: Read + Seek>(
468 var_types: &[VarType],
469 codes: &mut VecDeque<u8>,
472 ) -> Result<Option<Vec<Value>>, Error> {
473 let case_start = reader.stream_position()?;
474 let mut values = Vec::with_capacity(var_types.len());
475 for (i, &var_type) in var_types.iter().enumerate() {
477 let Some(code) = codes.pop_front() else {
478 let Some(new_codes): Option<[u8; 8]> = try_read_bytes(reader)? else {
482 let offset = reader.stream_position()?;
483 return Err(Error::EofInCompressedCase {
485 case_ofs: offset - case_start,
489 codes.extend(new_codes.into_iter());
494 1..=251 => match var_type {
495 VarType::Number => break Value::Number(Some(code as f64 - bias)),
497 break Value::String(endian.to_bytes(code as f64 - bias))
504 let offset = reader.stream_position()?;
505 return Err(Error::PartialCompressedCase {
507 case_ofs: offset - case_start,
511 253 => break Value::from_raw(var_type, read_bytes(reader)?, endian),
512 254 => match var_type {
513 VarType::String => break Value::String(*b" "), // XXX EBCDIC
515 return Err(Error::CompressedStringExpected {
517 case_ofs: reader.stream_position()? - case_start,
521 255 => match var_type {
522 VarType::Number => break Value::Number(None),
524 return Err(Error::CompressedNumberExpected {
526 case_ofs: reader.stream_position()? - case_start,
538 struct ZlibDecodeMultiple<R>
542 reader: Option<ZlibDecoder<R>>,
545 impl<R> ZlibDecodeMultiple<R>
549 fn new(reader: R) -> ZlibDecodeMultiple<R> {
551 reader: Some(ZlibDecoder::new(reader)),
556 impl<R> Read for ZlibDecodeMultiple<R>
560 fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
562 match self.reader.as_mut().unwrap().read(buf)? {
564 let inner = self.reader.take().unwrap().into_inner();
565 self.reader = Some(ZlibDecoder::new(inner));
573 impl<R> Seek for ZlibDecodeMultiple<R>
577 fn seek(&mut self, pos: SeekFrom) -> Result<u64, IoError> {
578 self.reader.as_mut().unwrap().get_mut().seek(pos)
583 state: Option<Box<dyn State>>,
587 pub fn new<R: Read + Seek + 'static>(reader: R) -> Result<Reader, Error> {
589 state: Some(state::new(reader)),
592 pub fn collect_headers(&mut self) -> Result<Vec<Record>, Error> {
593 let mut headers = Vec::new();
596 Record::EndOfHeaders(_) => break,
597 r => headers.push(r),
604 impl Iterator for Reader {
605 type Item = Result<Record, Error>;
607 fn next(&mut self) -> Option<Self::Item> {
608 match self.state.take()?.read() {
609 Ok(Some((record, next_state))) => {
610 self.state = Some(next_state);
614 Err(error) => Some(Err(error)),
619 impl FusedIterator for Reader {}
621 #[derive(Copy, Clone, PartialEq, Eq, Hash)]
622 pub struct Format(pub u32);
624 impl Debug for Format {
625 fn fmt(&self, f: &mut Formatter) -> FmtResult {
626 let type_ = format_name(self.0 >> 16);
627 let w = (self.0 >> 8) & 0xff;
628 let d = self.0 & 0xff;
629 write!(f, "{:06x} ({type_}{w}.{d})", self.0)
633 fn format_name(type_: u32) -> Cow<'static, str> {
672 _ => return format!("<unknown format {type_}>").into()
677 pub struct MissingValues {
678 /// Individual missing values, up to 3 of them.
679 pub values: Vec<Value>,
681 /// Optional range of missing values.
682 pub range: Option<(Value, Value)>,
685 impl Debug for MissingValues {
686 fn fmt(&self, f: &mut Formatter) -> FmtResult {
687 for (i, value) in self.values.iter().enumerate() {
691 write!(f, "{value:?}")?;
694 if let Some((low, high)) = self.range {
695 if !self.values.is_empty() {
698 write!(f, "{low:?} THRU {high:?}")?;
710 fn is_empty(&self) -> bool {
711 self.values.is_empty() && self.range.is_none()
714 fn read<R: Read + Seek>(
720 ) -> Result<MissingValues, Error> {
721 let (n_values, has_range) = match (width, code) {
722 (_, 0..=3) => (code, false),
723 (0, -2) => (0, true),
724 (0, -3) => (1, true),
725 (0, _) => return Err(Error::BadNumericMissingValueCode { offset, code }),
726 (_, _) => return Err(Error::BadStringMissingValueCode { offset, code }),
729 let var_type = VarType::from_width(width);
731 let mut values = Vec::new();
732 for _ in 0..n_values {
733 values.push(Value::read(r, var_type, endian)?);
735 let range = if has_range {
736 let low = Value::read(r, var_type, endian)?;
737 let high = Value::read(r, var_type, endian)?;
742 Ok(MissingValues { values, range })
747 pub struct Variable {
748 /// Offset from the start of the file to the start of the record.
751 /// Variable width, in the range -1..=255.
754 /// Variable name, padded on the right with spaces.
758 pub print_format: Format,
761 pub write_format: Format,
764 pub missing_values: MissingValues,
766 /// Optional variable label.
767 pub label: Option<UnencodedString>,
770 impl Debug for Variable {
771 fn fmt(&self, f: &mut Formatter) -> FmtResult {
778 } else if self.width == 0 {
781 "long string continuation record"
784 writeln!(f, "Print format: {:?}", self.print_format)?;
785 writeln!(f, "Write format: {:?}", self.write_format)?;
786 writeln!(f, "Name: {:?}", FallbackEncoding(&self.name))?;
787 writeln!(f, "Variable label: {:?}", self.label)?;
788 writeln!(f, "Missing values: {:?}", self.missing_values)
793 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Variable, Error> {
794 let offset = r.stream_position()?;
795 let width: i32 = endian.parse(read_bytes(r)?);
796 let has_variable_label: u32 = endian.parse(read_bytes(r)?);
797 let missing_value_code: i32 = endian.parse(read_bytes(r)?);
798 let print_format = Format(endian.parse(read_bytes(r)?));
799 let write_format = Format(endian.parse(read_bytes(r)?));
800 let name: [u8; 8] = read_bytes(r)?;
802 let label = match has_variable_label {
805 let len: u32 = endian.parse(read_bytes(r)?);
806 let read_len = len.min(65535) as usize;
807 let label = UnencodedString(read_vec(r, read_len)?);
809 let padding_bytes = Integer::next_multiple_of(&len, &4) - len;
810 let _ = read_vec(r, padding_bytes as usize)?;
815 return Err(Error::BadVariableLabelCode {
817 code: has_variable_label,
822 let missing_values = MissingValues::read(r, offset, width, missing_value_code, endian)?;
836 #[derive(Copy, Clone)]
837 pub struct UntypedValue(pub [u8; 8]);
839 impl Debug for UntypedValue {
840 fn fmt(&self, f: &mut Formatter) -> FmtResult {
841 let little: f64 = Endian::Little.parse(self.0);
842 let little = format!("{:?}", little);
843 let big: f64 = Endian::Big.parse(self.0);
844 let big = format!("{:?}", big);
845 let number = if little.len() <= big.len() {
850 write!(f, "{number}")?;
852 let string = fallback_encode(&self.0);
854 .split(|c: char| c == '\0' || c.is_control())
857 write!(f, "/\"{string}\"")?;
863 pub struct UnencodedString(Vec<u8>);
865 impl From<Vec<u8>> for UnencodedString {
866 fn from(source: Vec<u8>) -> Self {
871 impl From<&[u8]> for UnencodedString {
872 fn from(source: &[u8]) -> Self {
877 impl Debug for UnencodedString {
878 fn fmt(&self, f: &mut Formatter) -> FmtResult {
879 write!(f, "{:?}", FallbackEncoding(self.0.as_slice()))
884 pub struct ValueLabel {
885 /// Offset from the start of the file to the start of the record.
889 pub labels: Vec<(UntypedValue, UnencodedString)>,
892 impl Debug for ValueLabel {
893 fn fmt(&self, f: &mut Formatter) -> FmtResult {
894 for (value, label) in self.labels.iter() {
895 writeln!(f, "{value:?}: {label:?}")?;
902 /// Maximum number of value labels in a record.
903 pub const MAX: u32 = u32::MAX / 8;
905 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ValueLabel, Error> {
906 let offset = r.stream_position()?;
907 let n: u32 = endian.parse(read_bytes(r)?);
908 if n > ValueLabel::MAX {
909 return Err(Error::BadNumberOfValueLabels {
912 max: ValueLabel::MAX,
916 let mut labels = Vec::new();
918 let value = UntypedValue(read_bytes(r)?);
919 let label_len: u8 = endian.parse(read_bytes(r)?);
920 let label_len = label_len as usize;
921 let padded_len = Integer::next_multiple_of(&(label_len + 1), &8);
923 let mut label = read_vec(r, padded_len - 1)?;
924 label.truncate(label_len);
925 labels.push((value, UnencodedString(label)));
927 Ok(ValueLabel { offset, labels })
932 pub struct VarIndexes {
933 /// Offset from the start of the file to the start of the record.
936 /// The 0-based indexes of the variable indexes.
937 pub var_indexes: Vec<u32>,
940 impl Debug for VarIndexes {
941 fn fmt(&self, f: &mut Formatter) -> FmtResult {
942 write!(f, "apply to variables")?;
943 for var_index in self.var_indexes.iter() {
944 write!(f, " #{var_index}")?;
951 /// Maximum number of variable indexes in a record.
952 pub const MAX: u32 = u32::MAX / 8;
954 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<VarIndexes, Error> {
955 let offset = r.stream_position()?;
956 let n: u32 = endian.parse(read_bytes(r)?);
957 if n > VarIndexes::MAX {
958 return Err(Error::BadNumberOfVarIndexes {
961 max: VarIndexes::MAX,
964 let mut var_indexes = Vec::with_capacity(n as usize);
966 var_indexes.push(endian.parse(read_bytes(r)?));
976 #[derive(Clone, Debug)]
977 pub struct Document {
978 /// Offset from the start of the file to the start of the record.
981 /// The document, as an array of 80-byte lines.
982 pub lines: Vec<[u8; Document::LINE_LEN as usize]>,
986 /// Length of a line in a document. Document lines are fixed-length and
987 /// padded on the right with spaces.
988 pub const LINE_LEN: u32 = 80;
990 /// Maximum number of lines we will accept in a document. This is simply
991 /// the maximum number that will fit in a 32-bit space.
992 pub const MAX_LINES: u32 = i32::MAX as u32 / Self::LINE_LEN;
994 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Document, Error> {
995 let offset = r.stream_position()?;
996 let n: u32 = endian.parse(read_bytes(r)?);
998 0..=Self::MAX_LINES => Ok(Document {
999 pos: r.stream_position()?,
1001 .map(|_| read_bytes(r))
1002 .collect::<Result<Vec<_>, _>>()?,
1004 _ => Err(Error::BadDocumentLength {
1007 max: Self::MAX_LINES,
1017 const NAME: &'static str;
1018 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error>;
1021 trait ExtensionRecord
1026 const SIZE: Option<u32>;
1027 const COUNT: Option<u32>;
1028 const NAME: &'static str;
1029 fn parse(ext: &Extension, endian: Endian, warn: impl Fn(Error)) -> Result<Self, Error>;
1032 #[derive(Clone, Debug)]
1033 pub struct IntegerInfo {
1034 pub version: (i32, i32, i32),
1035 pub machine_code: i32,
1036 pub floating_point_rep: i32,
1037 pub compression_code: i32,
1038 pub endianness: i32,
1039 pub character_code: i32,
1042 impl ExtensionRecord for IntegerInfo {
1043 const SUBTYPE: u32 = 3;
1044 const SIZE: Option<u32> = Some(4);
1045 const COUNT: Option<u32> = Some(8);
1046 const NAME: &'static str = "integer record";
1048 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1049 ext.check_size::<Self>()?;
1051 let mut input = &ext.data[..];
1052 let data: Vec<i32> = (0..8)
1053 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1056 version: (data[0], data[1], data[2]),
1057 machine_code: data[3],
1058 floating_point_rep: data[4],
1059 compression_code: data[5],
1060 endianness: data[6],
1061 character_code: data[7],
1066 #[derive(Clone, Debug)]
1067 pub struct FloatInfo {
1073 impl ExtensionRecord for FloatInfo {
1074 const SUBTYPE: u32 = 4;
1075 const SIZE: Option<u32> = Some(8);
1076 const COUNT: Option<u32> = Some(3);
1077 const NAME: &'static str = "floating point record";
1079 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1080 ext.check_size::<Self>()?;
1082 let mut input = &ext.data[..];
1083 let data: Vec<f64> = (0..3)
1084 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1094 #[derive(Clone, Debug)]
1095 pub enum MultipleResponseType {
1097 value: UnencodedString,
1098 labels: CategoryLabels,
1102 #[derive(Clone, Debug)]
1103 pub struct MultipleResponseSet {
1104 pub name: UnencodedString,
1105 pub label: UnencodedString,
1106 pub mr_type: MultipleResponseType,
1107 pub vars: Vec<UnencodedString>,
1110 impl MultipleResponseSet {
1111 fn parse(input: &[u8]) -> Result<(MultipleResponseSet, &[u8]), Error> {
1112 let Some(equals) = input.iter().position(|&b| b == b'=') else {
1113 return Err(Error::TBD);
1115 let (name, input) = input.split_at(equals);
1116 let (mr_type, input) = match input.get(0) {
1117 Some(b'C') => (MultipleResponseType::MultipleCategory, &input[1..]),
1119 let (value, input) = parse_counted_string(&input[1..])?;
1121 MultipleResponseType::MultipleDichotomy {
1122 value: value.into(),
1123 labels: CategoryLabels::VarLabels,
1129 let Some(b' ') = input.get(1) else {
1130 return Err(Error::TBD);
1132 let input = &input[2..];
1133 let (labels, input) = if let Some(rest) = input.strip_prefix(b" 1 ") {
1134 (CategoryLabels::CountedValues, rest)
1135 } else if let Some(rest) = input.strip_prefix(b" 11 ") {
1136 (CategoryLabels::VarLabels, rest)
1138 return Err(Error::TBD);
1140 let (value, input) = parse_counted_string(input)?;
1142 MultipleResponseType::MultipleDichotomy {
1143 value: value.into(),
1149 _ => return Err(Error::TBD),
1151 let Some(b' ') = input.get(0) else {
1152 return Err(Error::TBD);
1154 let (label, mut input) = parse_counted_string(&input[1..])?;
1155 let mut vars = Vec::new();
1156 while input.get(0) == Some(&b' ') {
1157 input = &input[1..];
1158 let Some(length) = input.iter().position(|b| b" \n".contains(b)) else {
1159 return Err(Error::TBD);
1162 vars.push(input[..length].into());
1164 input = &input[length..];
1166 if input.get(0) != Some(&b'\n') {
1167 return Err(Error::TBD);
1169 while input.get(0) == Some(&b'\n') {
1170 input = &input[1..];
1173 MultipleResponseSet {
1175 label: label.into(),
1184 #[derive(Clone, Debug)]
1185 pub struct MultipleResponseRecord(Vec<MultipleResponseSet>);
1187 impl ExtensionRecord for MultipleResponseRecord {
1188 const SUBTYPE: u32 = 7;
1189 const SIZE: Option<u32> = Some(1);
1190 const COUNT: Option<u32> = None;
1191 const NAME: &'static str = "multiple response set record";
1193 fn parse(ext: &Extension, _endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1194 ext.check_size::<Self>()?;
1196 let mut input = &ext.data[..];
1197 let mut sets = Vec::new();
1198 while !input.is_empty() {
1199 let (set, rest) = MultipleResponseSet::parse(input)?;
1203 Ok(MultipleResponseRecord(sets))
1207 fn parse_counted_string(input: &[u8]) -> Result<(UnencodedString, &[u8]), Error> {
1208 let Some(space) = input.iter().position(|&b| b == b' ') else {
1209 return Err(Error::TBD);
1211 let Ok(length) = from_utf8(&input[..space]) else {
1212 return Err(Error::TBD);
1214 let Ok(length): Result<usize, _> = length.parse() else {
1215 return Err(Error::TBD);
1218 let input = &input[space + 1..];
1219 if input.len() < length {
1220 return Err(Error::TBD);
1223 let (string, rest) = input.split_at(length);
1224 Ok((string.into(), rest))
1227 pub struct ProductInfo(String);
1229 impl TextRecord for ProductInfo {
1230 const NAME: &'static str = "extra product info";
1231 fn parse(input: &str, _warn: impl Fn(Error)) -> Result<Self, Error> {
1232 Ok(ProductInfo(input.into()))
1236 #[derive(Clone, Debug)]
1237 pub struct VarDisplayRecord(pub Vec<u32>);
1239 impl ExtensionRecord for VarDisplayRecord {
1240 const SUBTYPE: u32 = 11;
1241 const SIZE: Option<u32> = Some(4);
1242 const COUNT: Option<u32> = None;
1243 const NAME: &'static str = "variable display record";
1245 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1246 ext.check_size::<Self>()?;
1248 let mut input = &ext.data[..];
1249 let display = (0..ext.count)
1250 .map(|_| endian.parse(read_bytes(&mut input).unwrap()))
1252 Ok(VarDisplayRecord(display))
1256 pub struct VariableSet {
1258 pub vars: Vec<String>,
1262 fn parse(input: &str) -> Result<Self, Error> {
1263 let (name, input) = input.split_once('=').ok_or(Error::TBD)?;
1264 let vars = input.split_ascii_whitespace().map(String::from).collect();
1272 pub struct VariableSetRecord(Vec<VariableSet>);
1274 impl TextRecord for VariableSetRecord {
1275 const NAME: &'static str = "variable set";
1276 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1277 let mut sets = Vec::new();
1278 for line in input.lines() {
1279 match VariableSet::parse(line) {
1280 Ok(set) => sets.push(set),
1281 Err(error) => warn(error),
1284 Ok(VariableSetRecord(sets))
1288 pub struct LongVariableName {
1289 pub short_name: String,
1290 pub long_name: String,
1293 pub struct LongVariableNameRecord(Vec<LongVariableName>);
1295 impl TextRecord for LongVariableNameRecord {
1296 const NAME: &'static str = "long variable names";
1297 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1298 let mut names = Vec::new();
1299 for pair in input.split('\t').filter(|s| !s.is_empty()) {
1300 if let Some((short_name, long_name)) = pair.split_once('=') {
1301 let name = LongVariableName {
1302 short_name: short_name.into(),
1303 long_name: long_name.into(),
1310 Ok(LongVariableNameRecord(names))
1314 pub struct VeryLongString {
1315 pub short_name: String,
1319 impl VeryLongString {
1320 fn parse(input: &str) -> Result<VeryLongString, Error> {
1321 let Some((short_name, length)) = input.split_once('=') else {
1322 return Err(Error::TBD);
1324 let length: usize = length.parse().map_err(|_| Error::TBD)?;
1326 short_name: short_name.into(),
1332 pub struct VeryLongStringRecord(Vec<VeryLongString>);
1334 impl TextRecord for VeryLongStringRecord {
1335 const NAME: &'static str = "very long strings";
1336 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1337 let mut very_long_strings = Vec::new();
1340 .map(|s| s.trim_end_matches('\t'))
1341 .filter(|s| !s.is_empty())
1343 match VeryLongString::parse(tuple) {
1344 Ok(vls) => very_long_strings.push(vls),
1345 Err(error) => warn(error),
1348 Ok(VeryLongStringRecord(very_long_strings))
1352 #[derive(Clone, Debug)]
1353 pub struct LongStringValueLabels {
1354 pub var_name: UnencodedString,
1357 /// `(value, label)` pairs, where each value is `width` bytes.
1358 pub labels: Vec<(UnencodedString, UnencodedString)>,
1361 #[derive(Clone, Debug)]
1362 pub struct LongStringValueLabelRecord(Vec<LongStringValueLabels>);
1364 impl ExtensionRecord for LongStringValueLabelRecord {
1365 const SUBTYPE: u32 = 21;
1366 const SIZE: Option<u32> = Some(1);
1367 const COUNT: Option<u32> = None;
1368 const NAME: &'static str = "long string value labels record";
1370 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1371 ext.check_size::<Self>()?;
1373 let mut input = &ext.data[..];
1374 let mut label_set = Vec::new();
1375 while !input.is_empty() {
1376 let var_name = read_string(&mut input, endian)?;
1377 let width: u32 = endian.parse(read_bytes(&mut input)?);
1378 let n_labels: u32 = endian.parse(read_bytes(&mut input)?);
1379 let mut labels = Vec::new();
1380 for _ in 0..n_labels {
1381 let value = read_string(&mut input, endian)?;
1382 let label = read_string(&mut input, endian)?;
1383 labels.push((value, label));
1385 label_set.push(LongStringValueLabels {
1391 Ok(LongStringValueLabelRecord(label_set))
1395 pub struct LongStringMissingValues {
1397 pub var_name: UnencodedString,
1400 pub missing_values: MissingValues,
1403 pub struct LongStringMissingValueSet(Vec<LongStringMissingValues>);
1405 impl ExtensionRecord for LongStringMissingValueSet {
1406 const SUBTYPE: u32 = 22;
1407 const SIZE: Option<u32> = Some(1);
1408 const COUNT: Option<u32> = None;
1409 const NAME: &'static str = "long string missing values record";
1411 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1412 ext.check_size::<Self>()?;
1414 let mut input = &ext.data[..];
1415 let mut missing_value_set = Vec::new();
1416 while !input.is_empty() {
1417 let var_name = read_string(&mut input, endian)?;
1418 let n_missing_values: u8 = endian.parse(read_bytes(&mut input)?);
1419 let value_len: u32 = endian.parse(read_bytes(&mut input)?);
1421 let offset = (ext.data.len() - input.len() - 8) as u64 + ext.offset;
1422 return Err(Error::BadLongMissingValueLength {
1423 record_offset: ext.offset,
1428 let mut values = Vec::new();
1429 for i in 0..n_missing_values {
1430 let value: [u8; 8] = read_bytes(&mut input)?;
1431 let numeric_value: u64 = endian.parse(value);
1432 let value = if i > 0 && numeric_value == 8 {
1433 // Tolerate files written by old, buggy versions of PSPP
1434 // where we believed that the value_length was repeated
1435 // before each missing value.
1436 read_bytes(&mut input)?
1440 values.push(Value::String(value));
1442 let missing_values = MissingValues {
1446 missing_value_set.push(LongStringMissingValues {
1451 Ok(LongStringMissingValueSet(missing_value_set))
1455 #[derive(Clone, Debug)]
1456 pub struct EncodingRecord(pub String);
1458 impl ExtensionRecord for EncodingRecord {
1459 const SUBTYPE: u32 = 20;
1460 const SIZE: Option<u32> = Some(1);
1461 const COUNT: Option<u32> = None;
1462 const NAME: &'static str = "encoding record";
1464 fn parse(ext: &Extension, _endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1465 ext.check_size::<Self>()?;
1468 String::from_utf8(ext.data.clone())
1469 .map_err(|_| Error::BadEncodingName { offset: ext.offset })?,
1474 pub struct Attribute {
1476 pub values: Vec<String>,
1480 fn parse<'a>(input: &'a str, warn: &impl Fn(Error)) -> Result<(Attribute, &'a str), Error> {
1481 let Some((name, mut input)) = input.split_once('(') else {
1482 return Err(Error::TBD);
1484 let mut values = Vec::new();
1486 let Some((value, rest)) = input.split_once('\n') else {
1487 return Err(Error::TBD);
1489 if let Some(stripped) = value
1491 .and_then(|value| value.strip_suffix('\''))
1493 values.push(stripped.into());
1496 values.push(value.into());
1498 if let Some(rest) = rest.strip_prefix(')') {
1512 pub struct AttributeSet(pub Vec<Attribute>);
1517 sentinel: Option<char>,
1518 warn: &impl Fn(Error),
1519 ) -> Result<(AttributeSet, &'a str), Error> {
1520 let mut attributes = Vec::new();
1522 match input.chars().next() {
1523 None => break input,
1524 c if c == sentinel => break &input[1..],
1526 let (attribute, rest) = Attribute::parse(input, &warn)?;
1527 attributes.push(attribute);
1532 Ok((AttributeSet(attributes), rest))
1536 pub struct FileAttributeRecord(AttributeSet);
1538 impl TextRecord for FileAttributeRecord {
1539 const NAME: &'static str = "data file attributes";
1540 fn parse(input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1541 let (set, rest) = AttributeSet::parse(input, None, &warn)?;
1542 if !rest.is_empty() {
1545 Ok(FileAttributeRecord(set))
1549 pub struct VarAttributeSet {
1550 pub long_var_name: String,
1551 pub attributes: AttributeSet,
1554 impl VarAttributeSet {
1557 warn: &impl Fn(Error),
1558 ) -> Result<(VarAttributeSet, &'a str), Error> {
1559 let Some((long_var_name, rest)) = input.split_once(':') else {
1560 return Err(Error::TBD);
1562 let (attributes, rest) = AttributeSet::parse(rest, Some('/'), warn)?;
1565 long_var_name: long_var_name.into(),
1573 pub struct VariableAttributeRecord(Vec<VarAttributeSet>);
1575 impl TextRecord for VariableAttributeRecord {
1576 const NAME: &'static str = "variable attributes";
1577 fn parse(mut input: &str, warn: impl Fn(Error)) -> Result<Self, Error> {
1578 let mut var_attribute_sets = Vec::new();
1579 while !input.is_empty() {
1580 match VarAttributeSet::parse(input, &warn) {
1581 Ok((var_attribute, rest)) => {
1582 var_attribute_sets.push(var_attribute);
1591 Ok(VariableAttributeRecord(var_attribute_sets))
1595 #[derive(Clone, Debug)]
1596 pub struct NumberOfCasesRecord {
1597 /// Always observed as 1.
1600 /// Number of cases.
1604 impl ExtensionRecord for NumberOfCasesRecord {
1605 const SUBTYPE: u32 = 16;
1606 const SIZE: Option<u32> = Some(8);
1607 const COUNT: Option<u32> = Some(2);
1608 const NAME: &'static str = "extended number of cases record";
1610 fn parse(ext: &Extension, endian: Endian, _warn: impl Fn(Error)) -> Result<Self, Error> {
1611 ext.check_size::<Self>()?;
1613 let mut input = &ext.data[..];
1614 let one = endian.parse(read_bytes(&mut input)?);
1615 let n_cases = endian.parse(read_bytes(&mut input)?);
1617 Ok(NumberOfCasesRecord { one, n_cases })
1621 #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
1622 pub enum TextExtensionSubtype {
1627 FileAttributes = 17,
1628 VariableAttributes = 18,
1631 #[derive(Clone, Debug)]
1632 pub struct TextExtension {
1633 pub subtype: TextExtensionSubtype,
1634 pub string: UnencodedString,
1637 #[derive(Clone, Debug)]
1638 pub struct Extension {
1639 /// Offset from the start of the file to the start of the record.
1645 /// Size of each data element.
1648 /// Number of data elements.
1651 /// `size * count` bytes of data.
1656 fn extension_record_size_requirements(extension: ExtensionType) -> (u32, u32) {
1658 /* Implemented record types. */
1659 ExtensionType::Integer => (4, 8),
1660 ExtensionType::Float => (8, 3),
1661 ExtensionType::VarSets => (1, 0),
1662 ExtensionType::Mrsets => (1, 0),
1663 ExtensionType::ProductInfo => (1, 0),
1664 ExtensionType::Display => (4, 0),
1665 ExtensionType::LongNames => (1, 0),
1666 ExtensionType::LongStrings => (1, 0),
1667 ExtensionType::Ncases => (8, 2),
1668 ExtensionType::FileAttrs => (1, 0),
1669 ExtensionType::VarAttrs => (1, 0),
1670 ExtensionType::Mrsets2 => (1, 0),
1671 ExtensionType::Encoding => (1, 0),
1672 ExtensionType::LongLabels => (1, 0),
1673 ExtensionType::LongMissing => (1, 0),
1675 /* Ignored record types. */
1676 ExtensionType::Date => (0, 0),
1677 ExtensionType::DataEntry => (0, 0),
1678 ExtensionType::Dataview => (0, 0),
1684 fn check_size<E: ExtensionRecord>(&self) -> Result<(), Error> {
1685 if let Some(expected_size) = E::SIZE {
1686 if self.size != expected_size {
1687 return Err(Error::BadRecordSize {
1688 offset: self.offset,
1689 record: E::NAME.into(),
1695 if let Some(expected_count) = E::COUNT {
1696 if self.count != expected_count {
1697 return Err(Error::BadRecordCount {
1698 offset: self.offset,
1699 record: E::NAME.into(),
1708 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<Record, Error> {
1709 let subtype = endian.parse(read_bytes(r)?);
1710 let offset = r.stream_position()?;
1711 let size: u32 = endian.parse(read_bytes(r)?);
1712 let count = endian.parse(read_bytes(r)?);
1713 let Some(product) = size.checked_mul(count) else {
1714 return Err(Error::ExtensionRecordTooLarge {
1721 let offset = r.stream_position()?;
1722 let data = read_vec(r, product as usize)?;
1723 let extension = Extension {
1731 IntegerInfo::SUBTYPE => Ok(Record::IntegerInfo(IntegerInfo::parse(
1736 FloatInfo::SUBTYPE => Ok(Record::FloatInfo(FloatInfo::parse(
1741 VarDisplayRecord::SUBTYPE => Ok(Record::VarDisplay(VarDisplayRecord::parse(
1746 MultipleResponseRecord::SUBTYPE | 19 => Ok(Record::MultipleResponse(
1747 MultipleResponseRecord::parse(&extension, endian, |_| ())?,
1749 LongStringValueLabelRecord::SUBTYPE => Ok(Record::LongStringValueLabels(
1750 LongStringValueLabelRecord::parse(&extension, endian, |_| ())?,
1752 EncodingRecord::SUBTYPE => Ok(Record::Encoding(EncodingRecord::parse(
1757 NumberOfCasesRecord::SUBTYPE => Ok(Record::NumberOfCases(NumberOfCasesRecord::parse(
1762 x if x == TextExtensionSubtype::VariableSets as u32 => {
1763 Ok(Record::VariableSets(UnencodedString(extension.data)))
1765 x if x == TextExtensionSubtype::ProductInfo as u32 => {
1766 Ok(Record::ProductInfo(UnencodedString(extension.data)))
1768 x if x == TextExtensionSubtype::LongNames as u32 => {
1769 Ok(Record::LongNames(UnencodedString(extension.data)))
1771 x if x == TextExtensionSubtype::LongStrings as u32 => {
1772 Ok(Record::LongStrings(UnencodedString(extension.data)))
1774 x if x == TextExtensionSubtype::FileAttributes as u32 => {
1775 Ok(Record::FileAttributes(UnencodedString(extension.data)))
1777 x if x == TextExtensionSubtype::VariableAttributes as u32 => {
1778 Ok(Record::VariableAttributes(UnencodedString(extension.data)))
1780 _ => Ok(Record::OtherExtension(extension)),
1785 #[derive(Clone, Debug)]
1786 pub struct ZHeader {
1787 /// File offset to the start of the record.
1790 /// File offset to the ZLIB data header.
1791 pub zheader_offset: u64,
1793 /// File offset to the ZLIB trailer.
1794 pub ztrailer_offset: u64,
1796 /// Length of the ZLIB trailer in bytes.
1797 pub ztrailer_len: u64,
1801 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZHeader, Error> {
1802 let offset = r.stream_position()?;
1803 let zheader_offset: u64 = endian.parse(read_bytes(r)?);
1804 let ztrailer_offset: u64 = endian.parse(read_bytes(r)?);
1805 let ztrailer_len: u64 = endian.parse(read_bytes(r)?);
1816 #[derive(Clone, Debug)]
1817 pub struct ZTrailer {
1818 /// File offset to the start of the record.
1821 /// Compression bias as a negative integer, e.g. -100.
1824 /// Always observed as zero.
1827 /// Uncompressed size of each block, except possibly the last. Only
1828 /// `0x3ff000` has been observed so far.
1829 pub block_size: u32,
1831 /// Block descriptors, always `(ztrailer_len - 24) / 24)` of them.
1832 pub blocks: Vec<ZBlock>,
1835 #[derive(Clone, Debug)]
1837 /// Offset of block of data if simple compression were used.
1838 pub uncompressed_ofs: u64,
1840 /// Actual offset within the file of the compressed data block.
1841 pub compressed_ofs: u64,
1843 /// The number of bytes in this data block after decompression. This is
1844 /// `block_size` in every data block but the last, which may be smaller.
1845 pub uncompressed_size: u32,
1847 /// The number of bytes in this data block, as stored compressed in this
1849 pub compressed_size: u32,
1853 fn read<R: Read + Seek>(r: &mut R, endian: Endian) -> Result<ZBlock, Error> {
1855 uncompressed_ofs: endian.parse(read_bytes(r)?),
1856 compressed_ofs: endian.parse(read_bytes(r)?),
1857 uncompressed_size: endian.parse(read_bytes(r)?),
1858 compressed_size: endian.parse(read_bytes(r)?),
1864 fn read<R: Read + Seek>(
1869 ) -> Result<Option<ZTrailer>, Error> {
1870 let start_offset = reader.stream_position()?;
1871 if reader.seek(SeekFrom::Start(ztrailer_ofs)).is_err() {
1874 let int_bias = endian.parse(read_bytes(reader)?);
1875 let zero = endian.parse(read_bytes(reader)?);
1876 let block_size = endian.parse(read_bytes(reader)?);
1877 let n_blocks: u32 = endian.parse(read_bytes(reader)?);
1878 let expected_n_blocks = (ztrailer_len - 24) / 24;
1879 if n_blocks as u64 != expected_n_blocks {
1880 return Err(Error::BadZlibTrailerNBlocks {
1881 offset: ztrailer_ofs,
1887 let blocks = (0..n_blocks)
1888 .map(|_| ZBlock::read(reader, endian))
1889 .collect::<Result<Vec<_>, _>>()?;
1890 reader.seek(SeekFrom::Start(start_offset))?;
1892 offset: ztrailer_ofs,
1901 fn try_read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<Option<[u8; N]>, IoError> {
1902 let mut buf = [0; N];
1903 let n = r.read(&mut buf)?;
1906 r.read_exact(&mut buf[n..])?;
1914 fn read_bytes<const N: usize, R: Read>(r: &mut R) -> Result<[u8; N], IoError> {
1915 let mut buf = [0; N];
1916 r.read_exact(&mut buf)?;
1920 fn read_vec<R: Read>(r: &mut R, n: usize) -> Result<Vec<u8>, IoError> {
1921 let mut vec = vec![0; n];
1922 r.read_exact(&mut vec)?;
1926 fn read_string<R: Read>(r: &mut R, endian: Endian) -> Result<UnencodedString, IoError> {
1927 let length: u32 = endian.parse(read_bytes(r)?);
1928 Ok(read_vec(r, length as usize)?.into())