Fix IndexOutOfBoundsException at FastJarFS

If there are more than 0xffff files in the jar,
we have to use Zip64 format

^KT-52786 Fixed
This commit is contained in:
Denis.Zharkov
2022-09-30 18:56:08 +02:00
committed by Space Team
parent fcabc60471
commit 337f461ad8
2 changed files with 101 additions and 9 deletions
@@ -28,6 +28,7 @@ class ZipEntryDescription(
}
private const val END_OF_CENTRAL_DIR_SIZE = 22
private const val END_OF_CENTRAL_DIR_ZIP64_SIZE = 56
private const val LOCAL_FILE_HEADER_EXTRA_OFFSET = 28
private const val LOCAL_FILE_HEADER_SIZE = LOCAL_FILE_HEADER_EXTRA_OFFSET + 2
@@ -62,15 +63,7 @@ fun MappedByteBuffer.contentsToByteArray(
fun MappedByteBuffer.parseCentralDirectory(): List<ZipEntryDescription> {
order(ByteOrder.LITTLE_ENDIAN)
var endOfCentralDirectoryOffset = capacity() - END_OF_CENTRAL_DIR_SIZE
while (endOfCentralDirectoryOffset >= 0) {
// header of "End of central directory"
if (getInt(endOfCentralDirectoryOffset) == 0x06054b50) break
endOfCentralDirectoryOffset--
}
val entriesNumber = getUnsignedShort(endOfCentralDirectoryOffset + 10)
val offsetOfCentralDirectory = getInt(endOfCentralDirectoryOffset + 16)
val (entriesNumber, offsetOfCentralDirectory) = parseCentralDirectoryRecordsNumberAndOffset()
var currentOffset = offsetOfCentralDirectory
@@ -129,4 +122,43 @@ fun MappedByteBuffer.parseCentralDirectory(): List<ZipEntryDescription> {
return result
}
private fun MappedByteBuffer.parseCentralDirectoryRecordsNumberAndOffset(): Pair<Int, Int> {
var endOfCentralDirectoryOffset = capacity() - END_OF_CENTRAL_DIR_SIZE
while (endOfCentralDirectoryOffset >= 0) {
// header of "End of central directory" (see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
if (getInt(endOfCentralDirectoryOffset) == 0x06054b50) break
endOfCentralDirectoryOffset--
}
val entriesNumber = getUnsignedShort(endOfCentralDirectoryOffset + 10)
val offsetOfCentralDirectory = getInt(endOfCentralDirectoryOffset + 16)
// Offset of start of central directory, relative to start of archive (or -1 for ZIP64)
// (see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
if (entriesNumber == 0xffff || offsetOfCentralDirectory == -1) return parseZip64CentralDirectoryRecordsNumberAndOffset()
return Pair(entriesNumber, offsetOfCentralDirectory)
}
private fun MappedByteBuffer.parseZip64CentralDirectoryRecordsNumberAndOffset(): Pair<Int, Int> {
var endOfCentralDirectoryOffset = capacity() - END_OF_CENTRAL_DIR_ZIP64_SIZE
while (endOfCentralDirectoryOffset >= 0) {
// header of "End of central directory" (see https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT)
if (getInt(endOfCentralDirectoryOffset) == 0x06064b50) break
endOfCentralDirectoryOffset--
}
val entriesNumber = getLong(endOfCentralDirectoryOffset + 32)
val offsetOfCentralDirectory = getLong(endOfCentralDirectoryOffset + 48)
require(entriesNumber <= Int.MAX_VALUE) {
"Jar $entriesNumber entries number equal or more than ${Int.MAX_VALUE} is not supported by FastJarFS"
}
require(offsetOfCentralDirectory <= Int.MAX_VALUE) {
"Jar $offsetOfCentralDirectory offset equal or more than ${Int.MAX_VALUE} is not supported by FastJarFS"
}
return Pair(entriesNumber.toInt(), offsetOfCentralDirectory.toInt())
}
private fun ByteBuffer.getUnsignedShort(offset: Int): Int = java.lang.Short.toUnsignedInt(getShort(offset))