+ struct areltdata *mapdata;
+ char nextname[17];
+ unsigned int counter;
+ bfd_byte *raw_armap, *rbase;
+ struct artdata *ardata = bfd_ardata (abfd);
+ char *stringbase;
+ unsigned int stringsize;
+ carsym *set;
+ int i = bfd_read ((PTR) nextname, 1, 16, abfd);
+
+ if (i == 0)
+ return true;
+ if (i != 16)
+ return false;
+
+ /* The archive has at least 16 bytes in it. */
+ if (bfd_seek (abfd, -16L, SEEK_CUR) != 0)
+ return false;
+
+ if (!strncmp (nextname, "__.SYMDEF ", 16)
+ || !strncmp (nextname, "__.SYMDEF/ ", 16)) /* old Linux archives */
+ return do_slurp_bsd_armap (abfd);
+
+ if (strncmp (nextname, "/ ", 16))
+ {
+ bfd_has_map (abfd) = false;
+ return true;
+ }
+
+ mapdata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
+ if (mapdata == NULL)
+ return false;
+
+ raw_armap = (bfd_byte *) bfd_zalloc (abfd, mapdata->parsed_size);
+ if (raw_armap == NULL)
+ {
+ byebye:
+ bfd_release (abfd, (PTR) mapdata);
+ return false;
+ }
+
+ if (bfd_read ((PTR) raw_armap, 1, mapdata->parsed_size, abfd) !=
+ mapdata->parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ byebyebye:
+ bfd_release (abfd, (PTR) raw_armap);
+ goto byebye;
+ }
+
+ ardata->symdef_count = bfd_h_get_16 (abfd, (PTR) raw_armap);
+
+ if (ardata->symdef_count * BSD_SYMDEF_SIZE
+ > mapdata->parsed_size - HPUX_SYMDEF_COUNT_SIZE)
+ {
+ /* Probably we're using the wrong byte ordering. */
+ bfd_set_error (bfd_error_wrong_format);
+ goto byebyebye;
+ }
+
+ ardata->cache = 0;
+
+ stringsize = bfd_h_get_32 (abfd, raw_armap + HPUX_SYMDEF_COUNT_SIZE);
+ /* Skip sym count and string sz. */
+ stringbase = ((char *) raw_armap
+ + HPUX_SYMDEF_COUNT_SIZE
+ + BSD_STRING_COUNT_SIZE);
+ rbase = (bfd_byte *) stringbase + stringsize;
+ ardata->symdefs = (carsym *) bfd_alloc (abfd,
+ (ardata->symdef_count
+ * BSD_SYMDEF_SIZE));
+ if (!ardata->symdefs)
+ return false;
+
+ for (counter = 0, set = ardata->symdefs;
+ counter < ardata->symdef_count;
+ counter++, set++, rbase += BSD_SYMDEF_SIZE)
+ {
+ set->name = bfd_h_get_32 (abfd, rbase) + stringbase;
+ set->file_offset = bfd_h_get_32 (abfd, rbase + BSD_SYMDEF_OFFSET_SIZE);
+ }
+
+ ardata->first_file_filepos = bfd_tell (abfd);
+ /* Pad to an even boundary if you have to. */
+ ardata->first_file_filepos += (ardata->first_file_filepos) % 2;
+ /* FIXME, we should provide some way to free raw_ardata when
+ we are done using the strings from it. For now, it seems
+ to be allocated on an objalloc anyway... */
+ bfd_has_map (abfd) = true;
+ return true;
+}
+\f
+/** Extended name table.
+
+ Normally archives support only 14-character filenames.
+
+ Intel has extended the format: longer names are stored in a special
+ element (the first in the archive, or second if there is an armap);
+ the name in the ar_hdr is replaced by <space><index into filename
+ element>. Index is the P.R. of an int (decimal). Data General have
+ extended the format by using the prefix // for the special element. */
+
+/* Returns false on error, true otherwise. */
+
+boolean
+_bfd_slurp_extended_name_table (abfd)
+ bfd *abfd;
+{
+ char nextname[17];
+ struct areltdata *namedata;
+
+ /* FIXME: Formatting sucks here, and in case of failure of BFD_READ,
+ we probably don't want to return true. */
+ bfd_seek (abfd, bfd_ardata (abfd)->first_file_filepos, SEEK_SET);
+ if (bfd_read ((PTR) nextname, 1, 16, abfd) == 16)
+ {
+ if (bfd_seek (abfd, (file_ptr) - 16, SEEK_CUR) != 0)
+ return false;
+
+ if (strncmp (nextname, "ARFILENAMES/ ", 16) != 0 &&
+ strncmp (nextname, "// ", 16) != 0)
+ {
+ bfd_ardata (abfd)->extended_names = NULL;
+ return true;
+ }
+
+ namedata = (struct areltdata *) _bfd_read_ar_hdr (abfd);
+ if (namedata == NULL)
+ return false;
+
+ bfd_ardata (abfd)->extended_names =
+ bfd_zalloc (abfd, namedata->parsed_size);
+ if (bfd_ardata (abfd)->extended_names == NULL)
+ {
+ byebye:
+ bfd_release (abfd, (PTR) namedata);
+ return false;
+ }
+
+ if (bfd_read ((PTR) bfd_ardata (abfd)->extended_names, 1,
+ namedata->parsed_size, abfd) != namedata->parsed_size)
+ {
+ if (bfd_get_error () != bfd_error_system_call)
+ bfd_set_error (bfd_error_malformed_archive);
+ bfd_release (abfd, (PTR) (bfd_ardata (abfd)->extended_names));
+ bfd_ardata (abfd)->extended_names = NULL;
+ goto byebye;
+ }
+
+ /* Since the archive is supposed to be printable if it contains
+ text, the entries in the list are newline-padded, not null
+ padded. In SVR4-style archives, the names also have a
+ trailing '/'. DOS/NT created archive often have \ in them
+ We'll fix all problems here.. */
+ {
+ char *temp = bfd_ardata (abfd)->extended_names;
+ char *limit = temp + namedata->parsed_size;
+ for (; temp < limit; ++temp)
+ {
+ if (*temp == '\012')
+ temp[temp[-1] == '/' ? -1 : 0] = '\0';
+ if (*temp == '\\')
+ *temp = '/';
+ }
+ }
+
+ /* Pad to an even boundary if you have to. */
+ bfd_ardata (abfd)->first_file_filepos = bfd_tell (abfd);
+ bfd_ardata (abfd)->first_file_filepos +=
+ (bfd_ardata (abfd)->first_file_filepos) % 2;
+
+ /* FIXME, we can't release namedata here because it was allocated
+ below extended_names on the objalloc... */
+#if 0
+ bfd_release (abfd, namedata);
+#endif
+ }
+ return true;
+}
+
+#ifdef VMS
+
+/* Return a copy of the stuff in the filename between any :]> and a
+ semicolon. */
+
+static const char *
+normalize (abfd, file)
+ bfd *abfd;
+ const char *file;
+{
+ CONST char *first;
+ CONST char *last;
+ char *copy;
+
+ first = file + strlen (file) - 1;
+ last = first + 1;
+
+ while (first != file)
+ {
+ if (*first == ';')
+ last = first;
+ if (*first == ':' || *first == ']' || *first == '>')
+ {
+ first++;
+ break;
+ }
+ first--;
+ }
+
+ copy = (char *) bfd_alloc (abfd, last - first + 1);
+ if (copy == NULL)
+ return NULL;
+
+ memcpy (copy, first, last - first);
+ copy[last - first] = 0;
+
+ return copy;
+}
+
+#else
+static const char *
+normalize (abfd, file)
+ bfd *abfd ATTRIBUTE_UNUSED;
+ const char *file;
+{
+ const char *filename = strrchr (file, '/');
+
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+ {
+ /* We could have foo/bar\\baz, or foo\\bar, or d:bar. */
+ char *bslash = strrchr (file, '\\');
+ if (filename == NULL || (bslash != NULL && bslash > filename))
+ filename = bslash;
+ if (filename == NULL && file[0] != '\0' && file[1] == ':')
+ filename = file + 1;
+ }
+#endif
+ if (filename != (char *) NULL)
+ filename++;
+ else
+ filename = file;
+ return filename;
+}
+#endif
+
+/* Build a BFD style extended name table. */
+
+boolean
+_bfd_archive_bsd_construct_extended_name_table (abfd, tabloc, tablen, name)
+ bfd *abfd;
+ char **tabloc;
+ bfd_size_type *tablen;
+ const char **name;
+{
+ *name = "ARFILENAMES/";
+ return _bfd_construct_extended_name_table (abfd, false, tabloc, tablen);
+}
+
+/* Build an SVR4 style extended name table. */
+
+boolean
+_bfd_archive_coff_construct_extended_name_table (abfd, tabloc, tablen, name)
+ bfd *abfd;
+ char **tabloc;
+ bfd_size_type *tablen;
+ const char **name;
+{
+ *name = "//";
+ return _bfd_construct_extended_name_table (abfd, true, tabloc, tablen);
+}
+
+/* Follows archive_head and produces an extended name table if
+ necessary. Returns (in tabloc) a pointer to an extended name
+ table, and in tablen the length of the table. If it makes an entry
+ it clobbers the filename so that the element may be written without
+ further massage. Returns true if it ran successfully, false if
+ something went wrong. A successful return may still involve a
+ zero-length tablen! */
+
+boolean
+_bfd_construct_extended_name_table (abfd, trailing_slash, tabloc, tablen)
+ bfd *abfd;
+ boolean trailing_slash;
+ char **tabloc;
+ bfd_size_type *tablen;
+{
+ unsigned int maxname = abfd->xvec->ar_max_namelen;