public static CoffArchiveMemberHeader read(BinaryReader reader, LongNamesMember longNames)
			throws IOException {
		align(reader);

		long headerOffset = reader.getPointerIndex();

		/*
		 * Decoding the name field:
		 * 
		 * "/nnn" - a slash followed by a ascii integer string indicates that the actual name
		 * is located at offset "nnn" in the "longnames" string table.
		 * 
		 * "#1/nnn" - a "#1/", followed by an ascii integer string indicates that the
		 * actual name is located at the beginning of the payload of this member, and its
		 * length is 'nnn' bytes.  The actual payload starts after the end of the name and
		 * its effective size needs to be reduced by the filename length. 
		 * 
		 * "name/"
		 * The field gives the name of the archive member directly.
		 * 
		 * "/"
		 * The archive member is one of the two linker members.
		 * Both of the linker members have this name.
		 * 
		 * "//"
		 * The archive member is the longname member, which
		 * consists of a series of terminated ASCII strings.
		 * The longnames member is the third archive member
		 */
		String name = reader.readAsciiString(headerOffset + CAMH_NAME_OFF, CAMH_NAME_LEN).trim();
		
		/*
		 * The number of seconds since 1/1/1970 UCT 
		 */
		String dateStr = reader.readAsciiString(headerOffset + CAMH_DATE_OFF, CAMH_DATE_LEN).trim();
		
		/*
		 * Ascii integer string or blank
		 */
		String userId =
			reader.readAsciiString(headerOffset + CAMH_USERID_OFF, CAMH_USERID_LEN).trim();
		
		/*
		 * Ascii integer string or blank
		 */
		String groupId =
			reader.readAsciiString(headerOffset + CAMH_GROUPID_OFF, CAMH_GROUPID_LEN).trim();
		
		/*
		 * Ascii integer string of ST_MODE value from the C run-time function _wstat
		 */
		String mode = reader.readAsciiString(headerOffset + CAMH_MODE_OFF, CAMH_MODE_LEN).trim();
		
		/*
		 * Ascii integer string representing the total size of the archive member,
		 * not including the header.  If the name is stored at the beginning of the
		 * payload (ie. name == "#1/nnn"), the member's effective size needs to be adjusted.
		 */
		String sizeStr = reader.readAsciiString(headerOffset + CAMH_SIZE_OFF, CAMH_SIZE_LEN).trim();
		
		/*
		 * Two byte Ascii string 0x60 0x0a ("'\n")
		 */
		String endOfHeader = reader.readAsciiString(headerOffset + CAMH_EOH_OFF, CAMH_EOH_LEN);
		
		if (!endOfHeader.equals(CAMH_EOH_MAGIC)) {
			throw new IOException("Bad EOH magic string: " + endOfHeader);
		}

		long payloadOffset = headerOffset + CAMH_PAYLOAD_OFF;
		
		long size;
		try {
			size = Long.parseLong(sizeStr);
		} catch ( NumberFormatException nfe ) {
			throw new IOException("Bad size value: " + sizeStr);
		}
		
		if (name.startsWith("#1/")) {
			try {
				int nameLen = Integer.parseInt(name.substring(3));
				// name seems to be padded with trailing nulls to put payload at aligned offset
				name = reader.readAsciiString(payloadOffset, nameLen);
				size -= nameLen;
				payloadOffset += nameLen;
			} catch ( NumberFormatException nfe ) {
				throw new IOException("Bad name len value: " + name);
			}
		}
		else if (name.matches("/[0-9]+") && longNames != null) {
			try {
				long offset = Long.parseLong(name.substring(1));
				name = longNames.getStringAtOffset(reader.getByteProvider(), offset);
				if (name.endsWith("/")) {
					name = name.substring(0, name.length() - 1);
				}
			}
			catch (NumberFormatException nfe) {
				throw new IOException("Bad long name offset: " + name);
			}
		}
		else if (name.startsWith("/")) {
			// don't do any tweaking of the name, keeps "/" and "//" intact.
		}
		else if (name.endsWith("/")) {
			name = name.substring(0, name.length() - 1);
		}

		long date = 0;
		try {
			if (!dateStr.isEmpty()) {
				date = Long.parseLong(dateStr) * 1000 /* convert from seconds to millis */;
			}
		}
		catch (NumberFormatException nfe) {
			Msg.warn(null, "COFF Archive: bad date value: [" + dateStr + "] in " +
					reader.getByteProvider().getName() + " for [" + name + "] at file offset 0x" +
					Long.toHexString(headerOffset));
		}

		reader.setPointerIndex(payloadOffset);

		return new CoffArchiveMemberHeader(name, date, userId, groupId, mode, size, payloadOffset,
			headerOffset);
	}
Reads a COFF archive member header from the specified {@link BinaryReader reader},
leaving the file position at the start of this member's payload.
<p>
The archive member's name is fixed up using the specified {@link LongNamesMember longNames}
object.

@param reader stream from which to read the COFF archive member header from
@param longNames optional, string table with long file names (only present in some 
COFF ar formats)
@return a new {@link CoffArchiveMemberHeader}
@throws IOException
Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/coff/archive/CoffArchiveMemberHeader.java