|
|
@@ -26,6 +26,8 @@ package org.apache.tools.tar; |
|
|
|
import java.io.IOException; |
|
|
|
import java.math.BigInteger; |
|
|
|
import java.nio.ByteBuffer; |
|
|
|
import java.util.Arrays; |
|
|
|
import java.util.WeakHashMap; |
|
|
|
|
|
|
|
import org.apache.tools.zip.ZipEncoding; |
|
|
|
import org.apache.tools.zip.ZipEncodingHelper; |
|
|
@@ -38,6 +40,10 @@ import org.apache.tools.zip.ZipEncodingHelper; |
|
|
|
public class TarUtils { |
|
|
|
|
|
|
|
private static final int BYTE_MASK = 255; |
|
|
|
private static final String NUL = "\0"; |
|
|
|
private static final String X = "X"; |
|
|
|
private static final String X_NUL = "X\0"; |
|
|
|
private static final WeakHashMap<ZipEncoding, byte[]> NUL_BY_ENCODING = new WeakHashMap<>(); |
|
|
|
|
|
|
|
static final ZipEncoding DEFAULT_ENCODING = |
|
|
|
ZipEncodingHelper.getZipEncoding(null); |
|
|
@@ -286,20 +292,75 @@ public class TarUtils { |
|
|
|
final ZipEncoding encoding) |
|
|
|
throws IOException { |
|
|
|
|
|
|
|
final byte[] nul = getNulByteEquivalent(encoding); |
|
|
|
final int nulLen = nul.length; |
|
|
|
int len = 0; |
|
|
|
for (; len < length; ++len) { |
|
|
|
if (buffer[offset + len] == 0) { |
|
|
|
break; |
|
|
|
if (nulLen == 1) { |
|
|
|
final byte nulByte = nul[0]; |
|
|
|
for (; len < length; ++len) { |
|
|
|
if (buffer[offset + len] == nulByte) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} else if (nulLen == 0) { |
|
|
|
len = length; |
|
|
|
} else { |
|
|
|
boolean found = false; |
|
|
|
for (; len <= length - nulLen; ++len) { |
|
|
|
// six-arg Arrays.equals requires Java 9 |
|
|
|
byte[] atOffset = Arrays.copyOfRange(buffer, offset + len, offset + len + nulLen); |
|
|
|
if (Arrays.equals(atOffset, nul)) { |
|
|
|
found = true; |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
if (!found) { |
|
|
|
len = length; |
|
|
|
} |
|
|
|
} |
|
|
|
if (len > 0) { |
|
|
|
final byte[] b = new byte[len]; |
|
|
|
System.arraycopy(buffer, offset, b, 0, len); |
|
|
|
final byte[] b = Arrays.copyOfRange(buffer, offset, offset + len); |
|
|
|
return encoding.decode(b); |
|
|
|
} |
|
|
|
return ""; |
|
|
|
} |
|
|
|
|
|
|
|
private static byte[] getNulByteEquivalent(ZipEncoding encoding) throws IOException { |
|
|
|
byte[] value = NUL_BY_ENCODING.get(encoding); |
|
|
|
if (value == null) { |
|
|
|
value = getUncachedNulByteEquivalent(encoding); |
|
|
|
NUL_BY_ENCODING.put(encoding, value); |
|
|
|
} |
|
|
|
return value; |
|
|
|
} |
|
|
|
|
|
|
|
private static byte[] getUncachedNulByteEquivalent(ZipEncoding encoding) throws IOException { |
|
|
|
final ByteBuffer nulBuffer = encoding.encode(NUL); |
|
|
|
final int nulLen = nulBuffer.limit() - nulBuffer.position(); |
|
|
|
final byte[] nul = |
|
|
|
Arrays.copyOfRange(nulBuffer.array(), nulBuffer.arrayOffset(), nulBuffer.arrayOffset() + nulLen); |
|
|
|
if (nulLen <= 1) { |
|
|
|
return nul; |
|
|
|
} |
|
|
|
final ByteBuffer xBuffer = encoding.encode(X); |
|
|
|
final int xBufferLen = xBuffer.limit() - xBuffer.position(); |
|
|
|
final ByteBuffer xNulBuffer = encoding.encode(X_NUL); |
|
|
|
final int xNulBufferLen = xNulBuffer.limit() - xNulBuffer.position(); |
|
|
|
if (xBufferLen >= xNulBufferLen) { |
|
|
|
return nul; |
|
|
|
} |
|
|
|
final byte[] x = |
|
|
|
Arrays.copyOfRange(xBuffer.array(), xBuffer.arrayOffset(), xBuffer.arrayOffset() + xBufferLen); |
|
|
|
final byte[] nulPrefix = |
|
|
|
Arrays.copyOfRange(xNulBuffer.array(), xNulBuffer.arrayOffset(), xNulBuffer.arrayOffset() + xBufferLen); |
|
|
|
if (Arrays.equals(x, nulPrefix)) { |
|
|
|
// strip of BOM or similar prefix |
|
|
|
return Arrays.copyOfRange(xNulBuffer.array(), xNulBuffer.arrayOffset() + xBufferLen, |
|
|
|
xNulBuffer.arrayOffset() + xNulBufferLen); |
|
|
|
} |
|
|
|
return nul; |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* Copy a name into a buffer. |
|
|
|
* Copies characters from the name into the buffer |
|
|
|