+ // Instantiate the ArchiveMember to be filled
+ ArchiveMember* member = new ArchiveMember(this);
+
+ // Extract the size and determine if the file is
+ // compressed or not (negative length).
+ int flags = 0;
+ int MemberSize = atoi(Hdr->size);
+ if (MemberSize < 0) {
+ flags |= ArchiveMember::CompressedFlag;
+ MemberSize = -MemberSize;
+ }
+
+ // Check the size of the member for sanity
+ if (At + MemberSize > End)
+ throw std::string("invalid member length in archive file");
+
+ // Check the member signature
+ if (!Hdr->checkSignature())
+ throw std::string("invalid file member signature");
+
+ // Convert and check the member name
+ // The empty name ( '/' and 15 blanks) is for a foreign (non-LLVM) symbol
+ // table. The special name "//" and 14 blanks is for a string table, used
+ // for long file names. This library doesn't generate either of those but
+ // it will accept them. If the name starts with #1/ and the remainder is
+ // digits, then those digits specify the length of the name that is
+ // stored immediately following the header. The special name
+ // __LLVM_SYM_TAB__ identifies the symbol table for LLVM bytecode.
+ // Anything else is a regular, short filename that is terminated with
+ // a '/' and blanks.
+
+ std::string pathname;
+ unsigned index;
+ switch (Hdr->name[0]) {
+ case '#':
+ if (Hdr->name[1] == '1' && Hdr->name[2] == '/') {
+ if (isdigit(Hdr->name[3])) {
+ unsigned len = atoi(&Hdr->name[3]);
+ pathname.assign(At, len);
+ At += len;
+ MemberSize -= len;
+ flags |= ArchiveMember::HasLongFilenameFlag;
+ } else
+ throw std::string("invalid long filename");
+ } else if (Hdr->name[1] == '_' &&
+ (0 == memcmp(Hdr->name, ARFILE_LLVM_SYMTAB_NAME, 16))) {
+ // The member is using a long file name (>15 chars) format.
+ // This format is standard for 4.4BSD and Mac OSX operating
+ // systems. LLVM uses it similarly. In this format, the
+ // remainder of the name field (after #1/) specifies the
+ // length of the file name which occupy the first bytes of
+ // the member's data. The pathname already has the #1/ stripped.
+ pathname.assign(ARFILE_LLVM_SYMTAB_NAME);
+ flags |= ArchiveMember::LLVMSymbolTableFlag;
+ }
+ break;
+ case '/':
+ if (Hdr->name[1]== '/') {
+ if (0 == memcmp(Hdr->name, ARFILE_STRTAB_NAME, 16)) {
+ pathname.assign(ARFILE_STRTAB_NAME);
+ flags |= ArchiveMember::StringTableFlag;
+ } else {
+ throw std::string("invalid string table name");
+ }
+ } else if (Hdr->name[1] == ' ') {
+ if (0 == memcmp(Hdr->name, ARFILE_SVR4_SYMTAB_NAME, 16)) {
+ pathname.assign(ARFILE_SVR4_SYMTAB_NAME);
+ flags |= ArchiveMember::SVR4SymbolTableFlag;
+ } else {
+ throw std::string("invalid SVR4 symbol table name");
+ }
+ } else if (isdigit(Hdr->name[1])) {
+ unsigned index = atoi(&Hdr->name[1]);
+ if (index < strtab.length()) {
+ const char* namep = strtab.c_str() + index;
+ const char* endp = strtab.c_str() + strtab.length();
+ const char* p = namep;
+ const char* last_p = p;
+ while (p < endp) {
+ if (*p == '\n' && *last_p == '/') {
+ pathname.assign(namep, last_p - namep);
+ flags |= ArchiveMember::HasLongFilenameFlag;
+ break;
+ }
+ last_p = p;
+ p++;
+ }
+ if (p >= endp)
+ throw std::string("missing name termiantor in string table");
+ } else {
+ throw std::string("name index beyond string table");
+ }
+ }
+ break;
+ case '_':
+ if (Hdr->name[1] == '_' &&
+ (0 == memcmp(Hdr->name, ARFILE_BSD4_SYMTAB_NAME, 16))) {
+ pathname.assign(ARFILE_BSD4_SYMTAB_NAME);
+ flags |= ArchiveMember::BSD4SymbolTableFlag;
+ break;
+ }
+ /* FALL THROUGH */
+
+ default:
+ char* slash = (char*) memchr(Hdr->name, '/', 16);
+ if (slash == 0)
+ slash = Hdr->name + 16;
+ pathname.assign(Hdr->name, slash - Hdr->name);
+ break;
+ }
+
+ // Determine if this is a bytecode file
+ switch (sys::IdentifyFileType(At, 4)) {
+ case sys::BytecodeFileType:
+ flags |= ArchiveMember::BytecodeFlag;
+ break;
+ case sys::CompressedBytecodeFileType:
+ flags |= ArchiveMember::CompressedBytecodeFlag;
+ flags &= ~ArchiveMember::CompressedFlag;
+ break;
+ default:
+ flags &= ~(ArchiveMember::BytecodeFlag|
+ ArchiveMember::CompressedBytecodeFlag);
+ break;
+ }
+
+ // Fill in fields of the ArchiveMember
+ member->next = 0;
+ member->prev = 0;
+ member->parent = this;
+ member->path.setFile(pathname);
+ member->info.fileSize = MemberSize;
+ member->info.modTime.fromEpochTime(atoi(Hdr->date));
+ sscanf(Hdr->mode, "%o", &(member->info.mode));
+ member->info.user = atoi(Hdr->uid);
+ member->info.group = atoi(Hdr->gid);
+ member->flags = flags;
+ member->data = At;