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 fn size_hint(&self) -> (usize, Option<usize>) {
807 match &self.0 {
808 SymbolIteratorInternal::None => (0, None),
809 SymbolIteratorInternal::Gnu { offsets, .. } => offsets.size_hint(),
810 SymbolIteratorInternal::Gnu64 { offsets, .. } => offsets.size_hint(),
811 SymbolIteratorInternal::Bsd { offsets, .. } => offsets.size_hint(),
812 SymbolIteratorInternal::Bsd64 { offsets, .. } => offsets.size_hint(),
813 SymbolIteratorInternal::Coff { indices, .. } => {
814 indices.size_hint()
816 }
817 }
818 }
819}
820
821#[derive(Debug, Clone, Copy)]
825pub struct ArchiveSymbol<'data> {
826 name: &'data [u8],
827 offset: ArchiveOffset,
828}
829
830impl<'data> ArchiveSymbol<'data> {
831 #[inline]
833 pub fn name(&self) -> &'data [u8] {
834 self.name
835 }
836
837 #[inline]
839 pub fn offset(&self) -> ArchiveOffset {
840 self.offset
841 }
842}
843
844fn parse_u64_digits(digits: &[u8], radix: u32) -> Option<u64> {
846 if let [b' ', ..] = digits {
847 return None;
848 }
849 let mut result: u64 = 0;
850 for &c in digits {
851 if c == b' ' {
852 return Some(result);
853 } else {
854 let x = (c as char).to_digit(radix)?;
855 result = result
856 .checked_mul(u64::from(radix))?
857 .checked_add(u64::from(x))?;
858 }
859 }
860 Some(result)
861}
862
863fn parse_sysv_extended_name<'data>(digits: &[u8], names: &'data [u8]) -> Result<&'data [u8], ()> {
866 let offset = parse_u64_digits(digits, 10).ok_or(())?;
867 let offset = offset.try_into().map_err(|_| ())?;
868 let name_data = names.get(offset..).ok_or(())?;
869 let len = memchr::memchr2(b'\n', b'\0', name_data).ok_or(())?;
870 if name_data[len] == b'\n' {
871 if len < 1 || name_data[len - 1] != b'/' {
872 Err(())
873 } else {
874 Ok(&name_data[..len - 1])
875 }
876 } else {
877 Ok(&name_data[..len])
878 }
879}
880
881fn parse_bsd_extended_name<'data, R: ReadRef<'data>>(
885 digits: &[u8],
886 data: R,
887 offset: &mut u64,
888 size: &mut u64,
889) -> Result<&'data [u8], ()> {
890 let len = parse_u64_digits(digits, 10).ok_or(())?;
891 *size = size.checked_sub(len).ok_or(())?;
892 let name_data = data.read_bytes(offset, len)?;
893 let name = match memchr::memchr(b'\0', name_data) {
894 Some(len) => &name_data[..len],
895 None => name_data,
896 };
897 Ok(name)
898}
899
900#[cfg(test)]
901mod tests {
902 use super::*;
903
904 #[test]
905 fn kind() {
906 let data = b"!<arch>\n";
907 let archive = ArchiveFile::parse(&data[..]).unwrap();
908 assert_eq!(archive.kind(), ArchiveKind::Unknown);
909
910 let data = b"\
911 !<arch>\n\
912 / 4 `\n\
913 0000";
914 let archive = ArchiveFile::parse(&data[..]).unwrap();
915 assert_eq!(archive.kind(), ArchiveKind::Gnu);
916
917 let data = b"\
918 !<arch>\n\
919 // 4 `\n\
920 0000";
921 let archive = ArchiveFile::parse(&data[..]).unwrap();
922 assert_eq!(archive.kind(), ArchiveKind::Gnu);
923
924 let data = b"\
925 !<arch>\n\
926 / 4 `\n\
927 0000\
928 // 4 `\n\
929 0000";
930 let archive = ArchiveFile::parse(&data[..]).unwrap();
931 assert_eq!(archive.kind(), ArchiveKind::Gnu);
932
933 let data = b"\
934 !<arch>\n\
935 /SYM64/ 4 `\n\
936 0000";
937 let archive = ArchiveFile::parse(&data[..]).unwrap();
938 assert_eq!(archive.kind(), ArchiveKind::Gnu64);
939
940 let data = b"\
941 !<arch>\n\
942 /SYM64/ 4 `\n\
943 0000\
944 // 4 `\n\
945 0000";
946 let archive = ArchiveFile::parse(&data[..]).unwrap();
947 assert_eq!(archive.kind(), ArchiveKind::Gnu64);
948
949 let data = b"\
950 !<arch>\n\
951 __.SYMDEF 4 `\n\
952 0000";
953 let archive = ArchiveFile::parse(&data[..]).unwrap();
954 assert_eq!(archive.kind(), ArchiveKind::Bsd);
955
956 let data = b"\
957 !<arch>\n\
958 #1/9 13 `\n\
959 __.SYMDEF0000";
960 let archive = ArchiveFile::parse(&data[..]).unwrap();
961 assert_eq!(archive.kind(), ArchiveKind::Bsd);
962
963 let data = b"\
964 !<arch>\n\
965 #1/16 20 `\n\
966 __.SYMDEF SORTED0000";
967 let archive = ArchiveFile::parse(&data[..]).unwrap();
968 assert_eq!(archive.kind(), ArchiveKind::Bsd);
969
970 let data = b"\
971 !<arch>\n\
972 __.SYMDEF_64 4 `\n\
973 0000";
974 let archive = ArchiveFile::parse(&data[..]).unwrap();
975 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
976
977 let data = b"\
978 !<arch>\n\
979 #1/12 16 `\n\
980 __.SYMDEF_640000";
981 let archive = ArchiveFile::parse(&data[..]).unwrap();
982 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
983
984 let data = b"\
985 !<arch>\n\
986 #1/19 23 `\n\
987 __.SYMDEF_64 SORTED0000";
988 let archive = ArchiveFile::parse(&data[..]).unwrap();
989 assert_eq!(archive.kind(), ArchiveKind::Bsd64);
990
991 let data = b"\
992 !<arch>\n\
993 / 4 `\n\
994 0000\
995 / 4 `\n\
996 0000\
997 // 4 `\n\
998 0000";
999 let archive = ArchiveFile::parse(&data[..]).unwrap();
1000 assert_eq!(archive.kind(), ArchiveKind::Coff);
1001
1002 let data = b"\
1003 <bigaf>\n\
1004 0 0 \
1005 0 0 \
1006 0 128 \
1007 6 0 \
1008 0 \0\0\0\0\0\0\0\0\0\0\0\0\
1009 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1010 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
1011 \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
1012 let archive = ArchiveFile::parse(&data[..]).unwrap();
1013 assert_eq!(archive.kind(), ArchiveKind::AixBig);
1014
1015 let data = b"\
1016 !<thin>\n\
1017 / 4 `\n\
1018 0000";
1019 let archive = ArchiveFile::parse(&data[..]).unwrap();
1020 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1021 assert!(archive.is_thin());
1022 }
1023
1024 #[test]
1025 fn gnu_names() {
1026 let data = b"\
1027 !<arch>\n\
1028 // 18 `\n\
1029 0123456789abcdef/\n\
1030 s p a c e/ 0 0 0 644 4 `\n\
1031 0000\
1032 0123456789abcde/0 0 0 644 3 `\n\
1033 odd\n\
1034 /0 0 0 0 644 4 `\n\
1035 even";
1036 let data = &data[..];
1037 let archive = ArchiveFile::parse(data).unwrap();
1038 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1039 let mut members = archive.members();
1040
1041 let member = members.next().unwrap().unwrap();
1042 assert_eq!(member.name(), b"s p a c e");
1043 assert_eq!(member.data(data).unwrap(), &b"0000"[..]);
1044
1045 let member = members.next().unwrap().unwrap();
1046 assert_eq!(member.name(), b"0123456789abcde");
1047 assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
1048
1049 let member = members.next().unwrap().unwrap();
1050 assert_eq!(member.name(), b"0123456789abcdef");
1051 assert_eq!(member.data(data).unwrap(), &b"even"[..]);
1052
1053 assert!(members.next().is_none());
1054 }
1055
1056 #[test]
1057 fn thin_gnu_names() {
1058 let data = b"\
1059 !<thin>\n\
1060 // 18 `\n\
1061 0123456789/abcde/\n\
1062 s p a c e/ 0 0 0 644 4 `\n\
1063 0123456789abcde/0 0 0 644 3 `\n\
1064 /0 0 0 0 644 4 `\n\
1065 ";
1066 let data = &data[..];
1067 let archive = ArchiveFile::parse(data).unwrap();
1068 assert_eq!(archive.kind(), ArchiveKind::Gnu);
1069 let mut members = archive.members();
1070
1071 let member = members.next().unwrap().unwrap();
1072 assert_eq!(member.name(), b"s p a c e");
1073 assert!(member.is_thin());
1074 assert_eq!(member.size(), 4);
1075 assert_eq!(member.data(data).unwrap(), &[]);
1076
1077 let member = members.next().unwrap().unwrap();
1078 assert_eq!(member.name(), b"0123456789abcde");
1079 assert!(member.is_thin());
1080 assert_eq!(member.size(), 3);
1081 assert_eq!(member.data(data).unwrap(), &[]);
1082
1083 let member = members.next().unwrap().unwrap();
1084 assert_eq!(member.name(), b"0123456789/abcde");
1085 assert!(member.is_thin());
1086 assert_eq!(member.size(), 4);
1087 assert_eq!(member.data(data).unwrap(), &[]);
1088
1089 assert!(members.next().is_none());
1090 }
1091
1092 #[test]
1093 fn bsd_names() {
1094 let data = b"\
1095 !<arch>\n\
1096 0123456789abcde 0 0 0 644 3 `\n\
1097 odd\n\
1098 #1/16 0 0 0 644 20 `\n\
1099 0123456789abcdefeven";
1100 let data = &data[..];
1101 let archive = ArchiveFile::parse(data).unwrap();
1102 assert_eq!(archive.kind(), ArchiveKind::Unknown);
1103 let mut members = archive.members();
1104
1105 let member = members.next().unwrap().unwrap();
1106 assert_eq!(member.name(), b"0123456789abcde");
1107 assert_eq!(member.data(data).unwrap(), &b"odd"[..]);
1108
1109 let member = members.next().unwrap().unwrap();
1110 assert_eq!(member.name(), b"0123456789abcdef");
1111 assert_eq!(member.data(data).unwrap(), &b"even"[..]);
1112
1113 assert!(members.next().is_none());
1114 }
1115
1116 #[test]
1117 fn aix_names() {
1118 let data = b"\
1119 <bigaf>\n\
1120 396 0 0 \
1121 128 262 0 \
1122 4 262 0 \
1123 1662610370 223 1 644 16 \
1124 0123456789abcdef`\nord\n\
1125 4 396 128 \
1126 1662610374 223 1 644 16 \
1127 fedcba9876543210`\nrev\n\
1128 94 0 262 \
1129 0 0 0 0 0 \
1130 `\n2 128 \
1131 262 0123456789abcdef\0fedcba9876543210\0";
1132 let data = &data[..];
1133 let archive = ArchiveFile::parse(data).unwrap();
1134 assert_eq!(archive.kind(), ArchiveKind::AixBig);
1135 let mut members = archive.members();
1136
1137 let member = members.next().unwrap().unwrap();
1138 assert_eq!(member.name(), b"0123456789abcdef");
1139 assert_eq!(member.data(data).unwrap(), &b"ord\n"[..]);
1140
1141 let member = members.next().unwrap().unwrap();
1142 assert_eq!(member.name(), b"fedcba9876543210");
1143 assert_eq!(member.data(data).unwrap(), &b"rev\n"[..]);
1144
1145 assert!(members.next().is_none());
1146 }
1147}