in src/main/java/org/apache/commons/compress/archivers/ar/ArArchiveInputStream.java [251:339]
public ArArchiveEntry getNextArEntry() throws IOException {
if (currentEntry != null) {
final long entryEnd = entryOffset + currentEntry.getLength();
final long skipped = org.apache.commons.io.IOUtils.skip(in, entryEnd - offset);
trackReadBytes(skipped);
currentEntry = null;
}
if (offset == 0) {
final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.HEADER);
final byte[] realized = IOUtils.readRange(in, expected.length);
final int read = realized.length;
trackReadBytes(read);
if (read != expected.length) {
throw new IOException("Failed to read header. Occurred at byte: " + getBytesRead());
}
if (!Arrays.equals(expected, realized)) {
throw new IOException("Invalid header " + ArchiveUtils.toAsciiString(realized));
}
}
if (offset % 2 != 0) {
if (in.read() < 0) {
// hit eof
return null;
}
trackReadBytes(1);
}
{
final int read = IOUtils.readFully(in, metaData);
trackReadBytes(read);
if (read == 0) {
return null;
}
if (read < metaData.length) {
throw new IOException("Truncated ar archive");
}
}
{
final byte[] expected = ArchiveUtils.toAsciiBytes(ArArchiveEntry.TRAILER);
final byte[] realized = IOUtils.readRange(in, expected.length);
final int read = realized.length;
trackReadBytes(read);
if (read != expected.length) {
throw new IOException("Failed to read entry trailer. Occurred at byte: " + getBytesRead());
}
if (!Arrays.equals(expected, realized)) {
throw new IOException("Invalid entry trailer. not read the content? Occurred at byte: " + getBytesRead());
}
}
entryOffset = offset;
// GNU ar uses a '/' to mark the end of the file name; this allows for the use of spaces without the use of an extended file name.
// entry name is stored as ASCII string
String temp = ArchiveUtils.toAsciiString(metaData, NAME_OFFSET, NAME_LEN).trim();
if (isGNUStringTable(temp)) { // GNU extended file names entry
currentEntry = readGNUStringTable(metaData, LENGTH_OFFSET, LENGTH_LEN);
return getNextArEntry();
}
long len;
try {
len = asLong(metaData, LENGTH_OFFSET, LENGTH_LEN);
} catch (final NumberFormatException ex) {
throw new IOException("Broken archive, unable to parse ar_size field as a number", ex);
}
if (temp.endsWith("/")) { // GNU terminator
temp = temp.substring(0, temp.length() - 1);
} else if (isGNULongName(temp)) {
final int off = ParsingUtils.parseIntValue(temp.substring(1)); // get the offset
temp = getExtendedName(off); // convert to the long name
} else if (isBSDLongName(temp)) {
temp = getBSDLongName(temp);
// entry length contained the length of the file name in
// addition to the real length of the entry.
// assume file name was ASCII, there is no "standard" otherwise
final int nameLen = temp.length();
len -= nameLen;
entryOffset += nameLen;
}
if (len < 0) {
throw new IOException("broken archive, entry with negative size");
}
try {
currentEntry = new ArArchiveEntry(temp, len, asInt(metaData, USER_ID_OFFSET, USER_ID_LEN, true),
asInt(metaData, GROUP_ID_OFFSET, GROUP_ID_LEN, true), asInt(metaData, FILE_MODE_OFFSET, FILE_MODE_LEN, 8),
asLong(metaData, LAST_MODIFIED_OFFSET, LAST_MODIFIED_LEN));
return currentEntry;
} catch (final NumberFormatException ex) {
throw new IOException("Broken archive, unable to parse entry metadata fields as numbers", ex);
}
}