1use core::convert::TryInto;
24use core::slice;
25
26use crate::archive;
27use crate::endian::{BigEndian as BE, LittleEndian as LE, U16Bytes, U32Bytes, U64Bytes};
28use crate::read::{self, Bytes, Error, ReadError, ReadRef};
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
32#[non_exhaustive]
33pub enum ArchiveKind {
34 Unknown,
36 Gnu,
38 Gnu64,
40 Bsd,
42 Bsd64,
46 Coff,
48 AixBig,
50}
51
52#[derive(Debug, Clone, Copy)]
54enum Members<'data> {
55 Common {
56 offset: u64,
57 end_offset: u64,
58 },
59 AixBig {
60 index: &'data [archive::AixMemberOffset],
61 },
62}
63
64#[derive(Debug, Clone, Copy)]
66pub struct ArchiveFile<'data, R: ReadRef<'data> = &'data [u8]> {
67 data: R,
68 kind: ArchiveKind,
69 members: Members<'data>,
70 symbols: (u64, u64),
71 names: &'data [u8],
72 thin: bool,
73}
74
75impl<'data, R: ReadRef<'data>> ArchiveFile<'data, R> {
76 pub fn parse(data: R) -> read::Result<Self> {
78 let len = data.len().read_error("Unknown archive length")?;
79 let mut tail = 0;
80 let magic = data
81 .read_bytes(&mut tail, archive::MAGIC.len() as u64)
82 .read_error("Invalid archive size")?;
83
84 let thin = if magic == archive::AIX_BIG_MAGIC {
85 return Self::parse_aixbig(data);
86 } else if magic == archive::THIN_MAGIC {
87 true
88 } else if magic == archive::MAGIC {
89 false
90 } else {
91 return Err(Error("Unsupported archive identifier"));
92 };
93
94 let mut members_offset = tail;
95 let members_end_offset = len;
96
97 let mut file = ArchiveFile {
98 data,
99 kind: ArchiveKind::Unknown,
100 members: Members::Common {
101 offset: 0,
102 end_offset: 0,
103 },
104 symbols: (0, 0),
105 names: &[],
106 thin,
107 };
108
109 if tail < len {
124 let member = ArchiveMember::parse(data, &mut tail, &[], thin)?;
125 if member.name == b"/" {
126 file.kind = ArchiveKind::Gnu;
128 file.symbols = member.file_range();
129 members_offset = tail;
130
131 if tail < len {
132 let member = ArchiveMember::parse(data, &mut tail, &[], thin)?;
133 if member.name == b"/" {
134 file.kind = ArchiveKind::Coff;
136 file.symbols = member.file_range();
137 members_offset = tail;
138
139 if tail < len {
140 let member = ArchiveMember::parse(data, &mut tail, &[], thin)?;
141 if member.name == b"//" {
142 file.names = member.data(data)?;
144 members_offset = tail;
145 }
146 }
147 if tail < len {
148 let member = ArchiveMember::parse(data, &mut tail, file.names, thin)?;
149 if member.name == b"/<ECSYMBOLS>/" {
150 members_offset = tail;
152 }
153 }
154 } else if member.name == b"//" {
155 file.names = member.data(data)?;
157 members_offset = tail;
158 }
159 }
160 } else if member.name == b"/SYM64/" {
161 file.kind = ArchiveKind::Gnu64;
163 file.symbols = member.file_range();
164 members_offset = tail;
165
166 if tail < len {
167 let member = ArchiveMember::parse(data, &mut tail, &[], thin)?;
168 if member.name == b"//" {
169 file.names = member.data(data)?;
171 members_offset = tail;
172 }
173 }
174 } else if member.name == b"//" {
175 file.kind = ArchiveKind::Gnu;
177 file.names = member.data(data)?;
178 members_offset = tail;
179 } else if member.name == b"__.SYMDEF" || member.name == b"__.SYMDEF SORTED" {
180 file.kind = ArchiveKind::Bsd;
182 file.symbols = member.file_range();
183 members_offset = tail;
184 } else if member.name == b"__.SYMDEF_64" || member.name == b"__.SYMDEF_64 SORTED" {
185 file.kind = ArchiveKind::Bsd64;
187 file.symbols = member.file_range();
188 members_offset = tail;
189 } else {
190 }
192 }
193 file.members = Members::Common {
194 offset: members_offset,
195 end_offset: members_end_offset,
196 };
197 Ok(file)
198 }
199
200 fn parse_aixbig(data: R) -> read::Result<Self> {
201 let mut tail = 0;
202
203 let file_header = data
204 .read::<archive::AixFileHeader>(&mut tail)
205 .read_error("Invalid AIX big archive file header")?;
206 debug_assert_eq!(file_header.magic, archive::AIX_BIG_MAGIC);
208
209 let mut file = ArchiveFile {
210 data,
211 kind: ArchiveKind::AixBig,
212 members: Members::AixBig { index: &[] },
213 symbols: (0, 0),
214 names: &[],
215 thin: false,
216 };
217
218 let symtbl64 = parse_u64_digits(&file_header.gst64off, 10)
221 .read_error("Invalid offset to 64-bit symbol table in AIX big archive")?;
222 if symtbl64 > 0 {
223 let member = ArchiveMember::parse_aixbig(data, symtbl64)?;
225 file.symbols = member.file_range();
226 } else {
227 let symtbl = parse_u64_digits(&file_header.gstoff, 10)
228 .read_error("Invalid offset to symbol table in AIX big archive")?;
229 if symtbl > 0 {
230 let member = ArchiveMember::parse_aixbig(data, symtbl)?;
232 file.symbols = member.file_range();
233 }
234 }
235
236 let member_table_offset = parse_u64_digits(&file_header.memoff, 10)
240 .read_error("Invalid offset for member table of AIX big archive")?;
241 if member_table_offset == 0 {
242 return Ok(file);
244 }
245
246 let member = ArchiveMember::parse_aixbig(data, member_table_offset)?;
248 let mut member_data = Bytes(member.data(data)?);
249
250 let members_count_bytes = member_data
255 .read_slice::<u8>(20)
256 .read_error("Missing member count in AIX big archive")?;
257 let members_count = parse_u64_digits(members_count_bytes, 10)
258 .and_then(|size| size.try_into().ok())
259 .read_error("Invalid member count in AIX big archive")?;
260 let index = member_data
261 .read_slice::<archive::AixMemberOffset>(members_count)
262 .read_error("Member count overflow in AIX big archive")?;
263 file.members = Members::AixBig { index };
264
265 Ok(file)
266 }
267
268 #[inline]
270 pub fn kind(&self) -> ArchiveKind {
271 self.kind
272 }
273
274 pub fn is_thin(&self) -> bool {
276 self.thin
277 }
278
279 #[inline]
283 pub fn members(&self) -> ArchiveMemberIterator<'data, R> {
284 ArchiveMemberIterator {
285 data: self.data,
286 members: self.members,
287 names: self.names,
288 thin: self.thin,
289 }
290 }
291
292 pub fn member(&self, member: ArchiveOffset) -> read::Result<ArchiveMember<'data>> {
294 match self.members {
295 Members::Common { offset, end_offset } => {
296 if member.0 < offset || member.0 >= end_offset {
297 return Err(Error("Invalid archive member offset"));
298 }
299 let mut offset = member.0;
300 ArchiveMember::parse(self.data, &mut offset, self.names, self.thin)
301 }
302 Members::AixBig { .. } => {
303 let offset = member.0;
304 ArchiveMember::parse_aixbig(self.data, offset)
305 }
306 }
307 }
308
309 pub fn symbols(&self) -> read::Result<Option<ArchiveSymbolIterator<'data>>> {
311 if self.symbols == (0, 0) {
312 return Ok(None);
313 }
314 let (offset, size) = self.symbols;
315 ArchiveSymbolIterator::new(self.kind, self.data, offset, size)
316 .read_error("Invalid archive symbol table")
317 .map(Some)
318 }
319}
320
321#[derive(Debug)]
323pub struct ArchiveMemberIterator<'data, R: ReadRef<'data> = &'data [u8]> {
324 data: R,
325 members: Members<'data>,
326 names: &'data [u8],
327 thin: bool,
328}
329
330impl<'data, R: ReadRef<'data>> Iterator for ArchiveMemberIterator<'data, R> {
331 type Item = read::Result<ArchiveMember<'data>>;
332
333 fn next(&mut self) -> Option<Self::Item> {
334 match &mut self.members {
335 Members::Common {
336 ref mut offset,
337 ref mut end_offset,
338 } => {
339 if *offset >= *end_offset {
340 return None;
341 }
342 let member = ArchiveMember::parse(self.data, offset, self.names, self.thin);
343 if member.is_err() {
344 *offset = *end_offset;
345 }
346 Some(member)
347 }
348 Members::AixBig { ref mut index } => match **index {
349 [] => None,
350 [ref first, ref rest @ ..] => {
351 *index = rest;
352 let member = ArchiveMember::parse_aixbig_index(self.data, first);
353 if member.is_err() {
354 *index = &[];
355 }
356 Some(member)
357 }
358 },
359 }
360 }
361}
362
363#[derive(Debug, Clone, Copy)]
365enum MemberHeader<'data> {
366 Common(&'data archive::Header),
368 AixBig(&'data archive::AixHeader),
370}
371
372#[derive(Debug)]
374pub struct ArchiveMember<'data> {
375 header: MemberHeader<'data>,
376 name: &'data [u8],
377 offset: u64,
379 size: u64,
380}
381
382impl<'data> ArchiveMember<'data> {
383 fn parse<R: ReadRef<'data>>(
387 data: R,
388 offset: &mut u64,
389 names: &'data [u8],
390 thin: bool,
391 ) -> read::Result<Self> {
392 let header = data
393 .read::<archive::Header>(offset)
394 .read_error("Invalid archive member header")?;
395 if header.terminator != archive::TERMINATOR {
396 return Err(Error("Invalid archive terminator"));
397 }
398
399 let header_file_size =
400 parse_u64_digits(&header.size, 10).read_error("Invalid archive member size")?;
401 let mut file_offset = *offset;
402 let mut file_size = header_file_size;
403
404 let name = if header.name[0] == b'/' && (header.name[1] as char).is_ascii_digit() {
405 parse_sysv_extended_name(&header.name[1..], names)
407 .read_error("Invalid archive extended name offset")?
408 } else if &header.name[..3] == b"#1/" && (header.name[3] as char).is_ascii_digit() {
409 parse_bsd_extended_name(&header.name[3..], data, &mut file_offset, &mut file_size)
411 .read_error("Invalid archive extended name length")?
412 } else if header.name[0] == b'/' {
413 let name_len = memchr::memchr(b' ', &header.name).unwrap_or(header.name.len());
414 &header.name[..name_len]
415 } else {
416 let name_len = memchr::memchr(b'/', &header.name)
420 .or_else(|| memchr::memchr(b' ', &header.name))
421 .unwrap_or(header.name.len());
422 &header.name[..name_len]
423 };
424
425 if thin && name != b"/" && name != b"//" && name != b"/SYM64/" {
427 return Ok(ArchiveMember {
428 header: MemberHeader::Common(header),
429 name,
430 offset: 0,
431 size: file_size,
432 });
433 }
434
435 *offset = offset
437 .checked_add(header_file_size)
438 .read_error("Archive member size is too large")?;
439 if (header_file_size & 1) != 0 {
441 *offset = offset.saturating_add(1);
442 }
443
444 Ok(ArchiveMember {
445 header: MemberHeader::Common(header),
446 name,
447 offset: file_offset,
448 size: file_size,
449 })
450 }
451
452 fn parse_aixbig_index<R: ReadRef<'data>>(
455 data: R,
456 index: &archive::AixMemberOffset,
457 ) -> read::Result<Self> {
458 let offset = parse_u64_digits(&index.0, 10)
459 .read_error("Invalid AIX big archive file member offset")?;
460 Self::parse_aixbig(data, offset)
461 }
462
463 fn parse_aixbig<R: ReadRef<'data>>(data: R, mut offset: u64) -> read::Result<Self> {
465 let header = data
468 .read::<archive::AixHeader>(&mut offset)
469 .read_error("Invalid AIX big archive member header")?;
470 let name_length = parse_u64_digits(&header.namlen, 10)
471 .read_error("Invalid AIX big archive member name length")?;
472 let name = data
473 .read_bytes(&mut offset, name_length)
474 .read_error("Invalid AIX big archive member name")?;
475
476 if offset & 1 != 0 {
480 offset = offset.saturating_add(1);
481 }
482 let terminator = data
484 .read_bytes(&mut offset, 2)
485 .read_error("Invalid AIX big archive terminator")?;
486 if terminator != archive::TERMINATOR {
487 return Err(Error("Invalid AIX big archive terminator"));
488 }
489
490 let size = parse_u64_digits(&header.size, 10)
491 .read_error("Invalid archive member size in AIX big archive")?;
492 Ok(ArchiveMember {
493 header: MemberHeader::AixBig(header),
494 name,
495 offset,
496 size,
497 })
498 }
499
500 #[inline]
504 pub fn header(&self) -> Option<&'data archive::Header> {
505 match self.header {
506 MemberHeader::Common(header) => Some(header),
507 _ => None,
508 }
509 }
510
511 #[inline]
515 pub fn aix_header(&self) -> Option<&'data archive::AixHeader> {
516 match self.header {
517 MemberHeader::AixBig(header) => Some(header),
518 _ => None,
519 }
520 }
521
522 #[inline]
526 pub fn name(&self) -> &'data [u8] {
527 self.name
528 }
529
530 #[inline]
532 pub fn date(&self) -> Option<u64> {
533 match &self.header {
534 MemberHeader::Common(header) => parse_u64_digits(&header.date, 10),
535 MemberHeader::AixBig(header) => parse_u64_digits(&header.date, 10),
536 }
537 }
538
539 #[inline]
541 pub fn uid(&self) -> Option<u64> {
542 match &self.header {
543 MemberHeader::Common(header) => parse_u64_digits(&header.uid, 10),
544 MemberHeader::AixBig(header) => parse_u64_digits(&header.uid, 10),
545 }
546 }
547
548 #[inline]
550 pub fn gid(&self) -> Option<u64> {
551 match &self.header {
552 MemberHeader::Common(header) => parse_u64_digits(&header.gid, 10),
553 MemberHeader::AixBig(header) => parse_u64_digits(&header.gid, 10),
554 }
555 }
556
557 #[inline]
559 pub fn mode(&self) -> Option<u64> {
560 match &self.header {
561 MemberHeader::Common(header) => parse_u64_digits(&header.mode, 8),
562 MemberHeader::AixBig(header) => parse_u64_digits(&header.mode, 8),
563 }
564 }
565
566 pub fn size(&self) -> u64 {
568 self.size
569 }
570
571 pub fn file_range(&self) -> (u64, u64) {
573 (self.offset, self.size)
574 }
575
576 pub fn is_thin(&self) -> bool {
580 self.offset == 0
581 }
582
583 #[inline]
587 pub fn data<R: ReadRef<'data>>(&self, data: R) -> read::Result<&'data [u8]> {
588 if self.is_thin() {
589 return Ok(&[]);
590 }
591 data.read_bytes_at(self.offset, self.size)
592 .read_error("Archive member size is too large")
593 }
594}
595
596#[derive(Debug, Clone, Copy)]
598pub struct ArchiveOffset(pub u64);
599
600#[derive(Debug, Clone)]
602pub struct ArchiveSymbolIterator<'data>(SymbolIteratorInternal<'data>);
603
604#[derive(Debug, Clone)]
605enum SymbolIteratorInternal<'data> {
606 None,
608 Gnu {
615 offsets: slice::Iter<'data, U32Bytes<BE>>,
616 names: Bytes<'data>,
617 },
618 Gnu64 {
625 offsets: slice::Iter<'data, U64Bytes<BE>>,
626 names: Bytes<'data>,
627 },
628 Bsd {
637 offsets: slice::Iter<'data, [U32Bytes<LE>; 2]>,
638 names: Bytes<'data>,
639 },
640 Bsd64 {
649 offsets: slice::Iter<'data, [U64Bytes<LE>; 2]>,
650 names: Bytes<'data>,
651 },
652 Coff {
661 members: &'data [U32Bytes<LE>],
662 indices: slice::Iter<'data, U16Bytes<LE>>,
663 names: Bytes<'data>,
664 },
665}
666
667impl<'data> ArchiveSymbolIterator<'data> {
668 fn new<R: ReadRef<'data>>(
669 kind: ArchiveKind,
670 data: R,
671 offset: u64,
672 size: u64,
673 ) -> Result<Self, ()> {
674 let mut data = data.read_bytes_at(offset, size).map(Bytes)?;
675 match kind {
676 ArchiveKind::Unknown => Ok(ArchiveSymbolIterator(SymbolIteratorInternal::None)),
677 ArchiveKind::Gnu => {
678 let offsets_count = data.read::<U32Bytes<BE>>()?.get(BE);
679 let offsets = data.read_slice::<U32Bytes<BE>>(offsets_count as usize)?;
680 Ok(ArchiveSymbolIterator(SymbolIteratorInternal::Gnu {
681 offsets: offsets.iter(),
682 names: data,
683 }))
684 }
685 ArchiveKind::Gnu64 => {
686 let offsets_count = data.read::<U64Bytes<BE>>()?.get(BE);
687 let offsets = data.read_slice::<U64Bytes<BE>>(offsets_count as usize)?;
688 Ok(ArchiveSymbolIterator(SymbolIteratorInternal::Gnu64 {
689 offsets: offsets.iter(),
690 names: data,
691 }))
692 }
693 ArchiveKind::Bsd => {
694 let offsets_size = data.read::<U32Bytes<LE>>()?.get(LE);
695 let offsets = data.read_slice::<[U32Bytes<LE>; 2]>(offsets_size as usize / 8)?;
696 let names_size = data.read::<U32Bytes<LE>>()?.get(LE);
697 let names = data.read_bytes(names_size as usize)?;
698 Ok(ArchiveSymbolIterator(SymbolIteratorInternal::Bsd {
699 offsets: offsets.iter(),
700 names,
701 }))
702 }
703 ArchiveKind::Bsd64 => {
704 let offsets_size = data.read::<U64Bytes<LE>>()?.get(LE);
705 let offsets = data.read_slice::<[U64Bytes<LE>; 2]>(offsets_size as usize / 16)?;
706 let names_size = data.read::<U64Bytes<LE>>()?.get(LE);
707 let names = data.read_bytes(names_size as usize)?;
708 Ok(ArchiveSymbolIterator(SymbolIteratorInternal::Bsd64 {
709 offsets: offsets.iter(),
710 names,
711 }))
712 }
713 ArchiveKind::Coff => {
714 let members_count = data.read::<U32Bytes<LE>>()?.get(LE);
715 let members = data.read_slice::<U32Bytes<LE>>(members_count as usize)?;
716 let indices_count = data.read::<U32Bytes<LE>>()?.get(LE);
717 let indices = data.read_slice::<U16Bytes<LE>>(indices_count as usize)?;
718 Ok(ArchiveSymbolIterator(SymbolIteratorInternal::Coff {
719 members,
720 indices: indices.iter(),
721 names: data,
722 }))
723 }
724 ArchiveKind::AixBig => Ok(ArchiveSymbolIterator(SymbolIteratorInternal::None)),
726 }
727 }
728}
729
730impl<'data> Iterator for ArchiveSymbolIterator<'data> {
731 type Item = read::Result<ArchiveSymbol<'data>>;
732
733 fn next(&mut self) -> Option<Self::Item> {
734 match &mut self.0 {
735 SymbolIteratorInternal::None => None,
736 SymbolIteratorInternal::Gnu { offsets, names } => {
737 let offset = offsets.next()?.get(BE);
738 Some(
739 names
740 .read_string()
741 .read_error("Missing archive symbol name")
742 .map(|name| ArchiveSymbol {
743 name,
744 offset: ArchiveOffset(offset.into()),
745 }),
746 )
747 }
748 SymbolIteratorInternal::Gnu64 { offsets, names } => {
749 let offset = offsets.next()?.get(BE);
750 Some(
751 names
752 .read_string()
753 .read_error("Missing archive symbol name")
754 .map(|name| ArchiveSymbol {
755 name,
756 offset: ArchiveOffset(offset),
757 }),
758 )
759 }
760 SymbolIteratorInternal::Bsd { offsets, names } => {
761 let entry = offsets.next()?;
762 Some(
763 names
764 .read_string_at(entry[0].get(LE) as usize)
765 .read_error("Invalid archive symbol name offset")
766 .map(|name| ArchiveSymbol {
767 name,
768 offset: ArchiveOffset(entry[1].get(LE).into()),
769 }),
770 )
771 }
772 SymbolIteratorInternal::Bsd64 { offsets, names } => {
773 let entry = offsets.next()?;
774 Some(
775 names
776 .read_string_at(entry[0].get(LE) as usize)
777 .read_error("Invalid archive symbol name offset")
778 .map(|name| ArchiveSymbol {
779 name,
780 offset: ArchiveOffset(entry[1].get(LE)),
781 }),
782 )
783 }
784 SymbolIteratorInternal::Coff {
785 members,
786 indices,
787 names,
788 } => {
789 let index = indices.next()?.get(LE).wrapping_sub(1);
790 let member = members
791 .get(index as usize)
792 .read_error("Invalid archive symbol member index");
793 let name = names
794 .read_string()
795 .read_error("Missing archive symbol name");
796 Some(member.and_then(|member| {
797 name.map(|name| ArchiveSymbol {
798 name,
799 offset: ArchiveOffset(member.get(LE).into()),
800 })
801 }))
802 }
803 }
804 }
805}
806
807#[derive(Debug, Clone, Copy)]
811pub struct ArchiveSymbol<'data> {
812 name: &'data [u8],
813 offset: ArchiveOffset,
814}
815
816impl<'data> ArchiveSymbol<'data> {
817 #[inline]
819 pub fn name(&self) -> &'data [u8] {
820 self.name
821 }
822
823 #[inline]
825 pub fn offset(&self) -> ArchiveOffset {
826 self.offset
827 }
828}
829
830fn parse_u64_digits(digits: &[u8], radix: u32) -> Option<u64> {
832 if let [b' ', ..] = digits {
833 return None;
834 }
835 let mut result: u64 = 0;
836 for &c in digits {
837 if c == b' ' {
838 return Some(result);
839 } else {
840 let x = (c as char).to_digit(radix)?;
841 result = result
842 .checked_mul(u64::from(radix))?
843 .checked_add(u64::from(x))?;
844 }
845 }
846 Some(result)
847}
848
849fn parse_sysv_extended_name<'data>(digits: &[u8], names: &'data [u8]) -> Result<&'data [u8], ()> {
852 let offset = parse_u64_digits(digits, 10).ok_or(())?;
853 let offset = offset.try_into().map_err(|_| ())?;
854 let name_data = names.get(offset..).ok_or(())?;
855 let len = memchr::memchr2(b'\n', b'\0', name_data).ok_or(())?;
856 if name_data[len] == b'\n' {
857 if len < 1 || name_data[len - 1] != b'/' {
858 Err(())
859 } else {
860 Ok(&name_data[..len - 1])
861 }
862 } else {
863 Ok(&name_data[..len])
864 }
865}
866
867fn parse_bsd_extended_name<'data, R: ReadRef<'data>>(
871 digits: &[u8],
872 data: R,
873 offset: &mut u64,
874 size: &mut u64,
875) -> Result<&'data [u8], ()> {
876 let len = parse_u64_digits(digits, 10).ok_or(())?;
877 *size = size.checked_sub(len).ok_or(())?;
878 let name_data = data.read_bytes(offset, len)?;
879 let name = match memchr::memchr(b'\0', name_data) {
880 Some(len) => &name_data[..len],
881 None => name_data,
882 };
883 Ok(name)
884}
885
886#[cfg(test)]
887mod tests {
888 use super::*;
889
890 #[test]
891 fn kind() {
892 let data = b"!<arch>\n";
893 let archive = ArchiveFile::parse(&data[..]).unwrap();
894 assert_eq!(archive.kind(), ArchiveKind::Unknown);
895
896 let data = b"\
897 !<arch>\n\
898 / 4 `\n\
899 0000";
900 let archive = ArchiveFile::parse(&data[..]).unwrap();
901 assert_eq!(archive.kind(), ArchiveKind::Gnu);
902
903 let data = b"\
904 !<arch>\n\
905 // 4 `\n\
906 0000";
907 let archive = ArchiveFile::parse(&data[..]).unwrap();
908 assert_eq!(archive.kind(), ArchiveKind::Gnu);
909
910 let data = b"\
911 !<arch>\n\
912 / 4 `\n\
913 0000\
914 // 4 `\n\
915 0000";
916 let archive = ArchiveFile::parse(&data[..]).unwrap();
917 assert_eq!(archive.kind(), ArchiveKind::Gnu);
918
919 let data = b"\
920 !<arch>\n\
921 /SYM64/ 4 `\n\
922 0000";
923 let archive = ArchiveFile::parse(&data[..]).unwrap();
924 assert_eq!(archive.kind(), ArchiveKind::Gnu64);
925
926 let data = b"\
927 !<arch>\n\
928 /SYM64/ 4 `\n\
929 0000\
930 // 4 `\n\
931 0000";
932 let archive = ArchiveFile::parse(&data[..]).unwrap();
933 assert_eq!(archive.kind(), ArchiveKind::Gnu64);
934
935 let data = b"\
936 !<arch>\n\
937 __.SYMDEF 4 `\n\
938 0000";
939 let archive = ArchiveFile::parse(&data[..]).unwrap();
940 assert_eq!(archive.kind(), ArchiveKind::Bsd);
941
942 let data = b"\
943 !<arch>\n\
944 #1/9 13 `\n\
945 __.SYMDEF0000";
946 let archive = ArchiveFile::parse(&data[..]).unwrap();
947 assert_eq!(archive.kind(), ArchiveKind::Bsd);
948
949 let data = b"\
950 !<arch>\n\
951 #1/16 20 `\n\
952 __.SYMDEF SORTED0000";
953 let archive = ArchiveFile::parse(&data[..]).unwrap();
954 assert_eq!(archive.kind(), ArchiveKind::Bsd);
955
956 let data = b"\
957 !<arch>\n\
958 __.SYMDEF_64 4 `\n\
959 0000";
960 let archive = ArchiveFile::parse(&data[..]).unwrap();
961 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
962
963 let data = b"\
964 !<arch>\n\
965 #1/12 16 `\n\
966 __.SYMDEF_640000";
967 let archive = ArchiveFile::parse(&data[..]).unwrap();
968 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
969
970 let data = b"\
971 !<arch>\n\
972 #1/19 23 `\n\
973 __.SYMDEF_64 SORTED0000";
974 let archive = ArchiveFile::parse(&data[..]).unwrap();
975 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
976
977 let data = b"\
978 !<arch>\n\
979 / 4 `\n\
980 0000\
981 / 4 `\n\
982 0000\
983 // 4 `\n\
984 0000";
985 let archive = ArchiveFile::parse(&data[..]).unwrap();
986 assert_eq!(archive.kind(), ArchiveKind::Coff);
987
988 let data = b"\
989 <bigaf>\n\
990 0 0 \
991 0 0 \
992 0 128 \
993 6 0 \
994 0 \0\0\0\0\0\0\0\0\0\0\0\0\
995 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
996 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
997 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
998 let archive = ArchiveFile::parse(&data[..]).unwrap();
999 assert_eq!(archive.kind(), ArchiveKind::AixBig);
1000
1001 let data = b"\
1002 !<thin>\n\
1003 / 4 `\n\
1004 0000";
1005 let archive = ArchiveFile::parse(&data[..]).unwrap();
1006 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1007 assert!(archive.is_thin());
1008 }
1009
1010 #[test]
1011 fn gnu_names() {
1012 let data = b"\
1013 !<arch>\n\
1014 // 18 `\n\
1015 0123456789abcdef/\n\
1016 s p a c e/ 0 0 0 644 4 `\n\
1017 0000\
1018 0123456789abcde/0 0 0 644 3 `\n\
1019 odd\n\
1020 /0 0 0 0 644 4 `\n\
1021 even";
1022 let data = &data[..];
1023 let archive = ArchiveFile::parse(data).unwrap();
1024 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1025 let mut members = archive.members();
1026
1027 let member = members.next().unwrap().unwrap();
1028 assert_eq!(member.name(), b"s p a c e");
1029 assert_eq!(member.data(data).unwrap(), &b"0000"[..]);
1030
1031 let member = members.next().unwrap().unwrap();
1032 assert_eq!(member.name(), b"0123456789abcde");
1033 assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
1034
1035 let member = members.next().unwrap().unwrap();
1036 assert_eq!(member.name(), b"0123456789abcdef");
1037 assert_eq!(member.data(data).unwrap(), &b"even"[..]);
1038
1039 assert!(members.next().is_none());
1040 }
1041
1042 #[test]
1043 fn thin_gnu_names() {
1044 let data = b"\
1045 !<thin>\n\
1046 // 18 `\n\
1047 0123456789/abcde/\n\
1048 s p a c e/ 0 0 0 644 4 `\n\
1049 0123456789abcde/0 0 0 644 3 `\n\
1050 /0 0 0 0 644 4 `\n\
1051 ";
1052 let data = &data[..];
1053 let archive = ArchiveFile::parse(data).unwrap();
1054 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1055 let mut members = archive.members();
1056
1057 let member = members.next().unwrap().unwrap();
1058 assert_eq!(member.name(), b"s p a c e");
1059 assert!(member.is_thin());
1060 assert_eq!(member.size(), 4);
1061 assert_eq!(member.data(data).unwrap(), &[]);
1062
1063 let member = members.next().unwrap().unwrap();
1064 assert_eq!(member.name(), b"0123456789abcde");
1065 assert!(member.is_thin());
1066 assert_eq!(member.size(), 3);
1067 assert_eq!(member.data(data).unwrap(), &[]);
1068
1069 let member = members.next().unwrap().unwrap();
1070 assert_eq!(member.name(), b"0123456789/abcde");
1071 assert!(member.is_thin());
1072 assert_eq!(member.size(), 4);
1073 assert_eq!(member.data(data).unwrap(), &[]);
1074
1075 assert!(members.next().is_none());
1076 }
1077
1078 #[test]
1079 fn bsd_names() {
1080 let data = b"\
1081 !<arch>\n\
1082 0123456789abcde 0 0 0 644 3 `\n\
1083 odd\n\
1084 #1/16 0 0 0 644 20 `\n\
1085 0123456789abcdefeven";
1086 let data = &data[..];
1087 let archive = ArchiveFile::parse(data).unwrap();
1088 assert_eq!(archive.kind(), ArchiveKind::Unknown);
1089 let mut members = archive.members();
1090
1091 let member = members.next().unwrap().unwrap();
1092 assert_eq!(member.name(), b"0123456789abcde");
1093 assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
1094
1095 let member = members.next().unwrap().unwrap();
1096 assert_eq!(member.name(), b"0123456789abcdef");
1097 assert_eq!(member.data(data).unwrap(), &b"even"[..]);
1098
1099 assert!(members.next().is_none());
1100 }
1101
1102 #[test]
1103 fn aix_names() {
1104 let data = b"\
1105 <bigaf>\n\
1106 396 0 0 \
1107 128 262 0 \
1108 4 262 0 \
1109 1662610370 223 1 644 16 \
1110 0123456789abcdef`\nord\n\
1111 4 396 128 \
1112 1662610374 223 1 644 16 \
1113 fedcba9876543210`\nrev\n\
1114 94 0 262 \
1115 0 0 0 0 0 \
1116 `\n2 128 \
1117 262 0123456789abcdef\0fedcba9876543210\0";
1118 let data = &data[..];
1119 let archive = ArchiveFile::parse(data).unwrap();
1120 assert_eq!(archive.kind(), ArchiveKind::AixBig);
1121 let mut members = archive.members();
1122
1123 let member = members.next().unwrap().unwrap();
1124 assert_eq!(member.name(), b"0123456789abcdef");
1125 assert_eq!(member.data(data).unwrap(), &b"ord\n"[..]);
1126
1127 let member = members.next().unwrap().unwrap();
1128 assert_eq!(member.name(), b"fedcba9876543210");
1129 assert_eq!(member.data(data).unwrap(), &b"rev\n"[..]);
1130
1131 assert!(members.next().is_none());
1132 }
1133}