CLI implementation & linting (#2)
Implement a basic CLI interface & add linting to the project. Reviewed-on: #2
This commit is contained in:
@@ -15,7 +15,7 @@ internal class CentralDirectoryFileHeader(
|
||||
val disk: UShort,
|
||||
val localHeaderOffset: UInt,
|
||||
val fileName: String,
|
||||
val extraFieldRecords: List<ExtraFieldRecord>
|
||||
val extraFieldRecords: List<ExtraFieldRecord>,
|
||||
) {
|
||||
val size: Int
|
||||
get() = SIZE + nameLength.toInt() + extraFieldLength.toInt() + commentLength.toInt()
|
||||
@@ -32,65 +32,85 @@ internal class CentralDirectoryFileHeader(
|
||||
* @return A `CentralDirectoryFileHeader`.
|
||||
*/
|
||||
@Throws(InvalidDataException::class)
|
||||
fun fromByteArray(data: ByteArray, offset: Int): CentralDirectoryFileHeader {
|
||||
fun fromByteArray(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
): CentralDirectoryFileHeader {
|
||||
if (data.size - offset < SIZE) {
|
||||
throw InvalidDataException("CEN must be at least 46 bytes")
|
||||
}
|
||||
val buf = ByteBuffer.wrap(data, offset, 46).order(ByteOrder.LITTLE_ENDIAN)
|
||||
if (buf.getInt().toUInt() != SIGNATURE) {
|
||||
throw InvalidSignatureException("Invalid signature")
|
||||
throw InvalidDataException("Invalid signature")
|
||||
}
|
||||
|
||||
val extraFieldRecords = mutableListOf<ExtraFieldRecord>()
|
||||
val nameLength = buf.getShort(offset + 28).toUShort()
|
||||
buf.position(offset + 20)
|
||||
val cen = CentralDirectoryFileHeader(
|
||||
compressedSize = buf.getInt().toUInt(),
|
||||
uncompressedSize = buf.getInt().toUInt(),
|
||||
nameLength = nameLength
|
||||
.also { buf.position(offset + 30) },
|
||||
extraFieldLength = buf.getShort().toUShort(),
|
||||
commentLength = buf.getShort().toUShort(),
|
||||
disk = buf.getShort().toUShort()
|
||||
.also { buf.position(offset + 42) },
|
||||
localHeaderOffset = buf.getInt().toUInt(),
|
||||
fileName = String(data.sliceArray(offset + SIZE..<offset + SIZE + nameLength.toInt())),
|
||||
extraFieldRecords = extraFieldRecords
|
||||
)
|
||||
val cen =
|
||||
CentralDirectoryFileHeader(
|
||||
compressedSize = buf.getInt().toUInt(),
|
||||
uncompressedSize = buf.getInt().toUInt(),
|
||||
nameLength =
|
||||
nameLength
|
||||
.also { buf.position(offset + 30) },
|
||||
extraFieldLength = buf.getShort().toUShort(),
|
||||
commentLength = buf.getShort().toUShort(),
|
||||
disk =
|
||||
buf.getShort().toUShort()
|
||||
.also { buf.position(offset + 42) },
|
||||
localHeaderOffset = buf.getInt().toUInt(),
|
||||
fileName = String(data.sliceArray(offset + SIZE..<offset + SIZE + nameLength.toInt())),
|
||||
extraFieldRecords = extraFieldRecords,
|
||||
)
|
||||
if (data.size - offset < cen.size) {
|
||||
throw InvalidDataException("CEN is too short")
|
||||
}
|
||||
|
||||
// Parse extra field records
|
||||
val extraFieldsBuf = ByteBuffer.wrap(
|
||||
data, offset + SIZE + cen.nameLength.toInt(), cen.extraFieldLength.toInt()
|
||||
).order(ByteOrder.LITTLE_ENDIAN)
|
||||
val extraFieldsBuf =
|
||||
ByteBuffer.wrap(
|
||||
data,
|
||||
offset + SIZE + cen.nameLength.toInt(),
|
||||
cen.extraFieldLength.toInt(),
|
||||
).order(ByteOrder.LITTLE_ENDIAN)
|
||||
while (extraFieldsBuf.remaining() > 0) {
|
||||
val id = extraFieldsBuf.getShort().toUShort()
|
||||
val size = extraFieldsBuf.getShort().toUShort()
|
||||
extraFieldRecords.add(when (id) {
|
||||
Zip64ExtraFieldRecord.ID -> {
|
||||
Zip64ExtraFieldRecord(
|
||||
size,
|
||||
if (cen.uncompressedSize == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else null,
|
||||
if (cen.compressedSize == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else null,
|
||||
if (cen.localHeaderOffset == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else null,
|
||||
if (cen.disk == 0xffffU.toUShort()) {
|
||||
extraFieldsBuf.getInt().toUInt()
|
||||
} else null
|
||||
)
|
||||
}
|
||||
else -> {
|
||||
extraFieldsBuf.position(extraFieldsBuf.position() + size.toInt())
|
||||
ExtraFieldRecord(id, size)
|
||||
}
|
||||
})
|
||||
extraFieldRecords.add(
|
||||
when (id) {
|
||||
Zip64ExtraFieldRecord.ID -> {
|
||||
Zip64ExtraFieldRecord(
|
||||
size,
|
||||
if (cen.uncompressedSize == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else {
|
||||
null
|
||||
},
|
||||
if (cen.compressedSize == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else {
|
||||
null
|
||||
},
|
||||
if (cen.localHeaderOffset == 0xffffffffU) {
|
||||
extraFieldsBuf.getLong().toULong()
|
||||
} else {
|
||||
null
|
||||
},
|
||||
if (cen.disk == 0xffffU.toUShort()) {
|
||||
extraFieldsBuf.getInt().toUInt()
|
||||
} else {
|
||||
null
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
else -> {
|
||||
extraFieldsBuf.position(extraFieldsBuf.position() + size.toInt())
|
||||
ExtraFieldRecord(id, size)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return cen
|
||||
|
@@ -7,11 +7,12 @@ import java.nio.ByteOrder
|
||||
* Represents a partial ZIP64 end of central directory locator.
|
||||
*/
|
||||
internal class EndOfCentralDirectoryLocator(
|
||||
val endOfCentralDirectory64Offset: ULong
|
||||
val endOfCentralDirectory64Offset: ULong,
|
||||
) {
|
||||
companion object {
|
||||
const val SIGNATURE = 0x07064b50U
|
||||
const val SIZE = 20
|
||||
|
||||
/**
|
||||
* Create `EndOfCentralDirectoryLocator` from raw byte data.
|
||||
* @throws InvalidDataException Provided `ByteArray` is not a supported EOCD locator.
|
||||
@@ -20,13 +21,16 @@ internal class EndOfCentralDirectoryLocator(
|
||||
* @return A `EndOfCentralDirectoryLocator`.
|
||||
*/
|
||||
@Throws(InvalidDataException::class)
|
||||
fun fromByteArray(data: ByteArray, offset: Int): EndOfCentralDirectoryLocator {
|
||||
fun fromByteArray(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
): EndOfCentralDirectoryLocator {
|
||||
if (data.size - offset < SIZE) {
|
||||
throw InvalidDataException("EOCD64 locator must be at least 20 bytes")
|
||||
}
|
||||
val buf = ByteBuffer.wrap(data, offset, SIZE).order(ByteOrder.LITTLE_ENDIAN)
|
||||
if (buf.getInt().toUInt() != SIGNATURE) {
|
||||
throw InvalidSignatureException("Invalid signature")
|
||||
throw InvalidDataException("Invalid signature")
|
||||
}
|
||||
buf.position(offset + 8)
|
||||
return EndOfCentralDirectoryLocator(buf.getLong().toULong())
|
||||
|
@@ -7,14 +7,14 @@ import java.nio.ByteOrder
|
||||
* Represents a partial ZIP end of central directory record.
|
||||
*/
|
||||
internal class EndOfCentralDirectoryRecord(
|
||||
val centralDirectoryOffset: UInt
|
||||
val centralDirectoryOffset: UInt,
|
||||
) {
|
||||
fun eocd64Required(): Boolean =
|
||||
centralDirectoryOffset == 0xffffffffU
|
||||
fun eocd64Required(): Boolean = centralDirectoryOffset == 0xffffffffU
|
||||
|
||||
companion object {
|
||||
const val SIGNATURE = 0x06054b50U
|
||||
const val SIZE = 22
|
||||
|
||||
/**
|
||||
* Create `EndOfCentralDirectoryRecord` from raw byte data.
|
||||
* @throws InvalidDataException Provided `ByteArray` is not a supported EOCD64.
|
||||
@@ -23,17 +23,20 @@ internal class EndOfCentralDirectoryRecord(
|
||||
* @return A `EndOfCentralDirectoryRecord`.
|
||||
*/
|
||||
@Throws(InvalidDataException::class)
|
||||
fun fromByteArray(data: ByteArray, offset: Int): EndOfCentralDirectoryRecord {
|
||||
fun fromByteArray(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
): EndOfCentralDirectoryRecord {
|
||||
if (data.size - offset < SIZE) {
|
||||
throw InvalidDataException("EOCD must be at least 22 bytes")
|
||||
}
|
||||
val buf = ByteBuffer.wrap(data, offset, SIZE).order(ByteOrder.LITTLE_ENDIAN)
|
||||
if (buf.getInt().toUInt() != SIGNATURE) {
|
||||
throw InvalidSignatureException("Invalid signature")
|
||||
throw InvalidDataException("Invalid signature")
|
||||
}
|
||||
buf.position(offset + 16)
|
||||
return EndOfCentralDirectoryRecord(
|
||||
centralDirectoryOffset = buf.getInt().toUInt()
|
||||
centralDirectoryOffset = buf.getInt().toUInt(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -7,11 +7,12 @@ import java.nio.ByteOrder
|
||||
* Represents a partial ZIP64 end of central directory record.
|
||||
*/
|
||||
internal class EndOfCentralDirectoryRecord64(
|
||||
val centralDirectoryOffset: ULong
|
||||
val centralDirectoryOffset: ULong,
|
||||
) {
|
||||
companion object {
|
||||
const val SIGNATURE = 0x06064b50U
|
||||
const val SIZE = 56
|
||||
|
||||
/**
|
||||
* Create `EndOfCentralDirectoryRecord64` from raw byte data.
|
||||
* @throws InvalidDataException Provided `ByteArray` is not a supported EOCD.
|
||||
@@ -20,17 +21,20 @@ internal class EndOfCentralDirectoryRecord64(
|
||||
* @return A `EndOfCentralDirectoryRecord64`.
|
||||
*/
|
||||
@Throws(InvalidDataException::class)
|
||||
fun fromByteArray(data: ByteArray, offset: Int): EndOfCentralDirectoryRecord64 {
|
||||
fun fromByteArray(
|
||||
data: ByteArray,
|
||||
offset: Int,
|
||||
): EndOfCentralDirectoryRecord64 {
|
||||
if (data.size - offset < SIZE) {
|
||||
throw InvalidDataException("EOCD64 must be at least 56 bytes")
|
||||
}
|
||||
val buf = ByteBuffer.wrap(data, offset, SIZE).order(ByteOrder.LITTLE_ENDIAN)
|
||||
if (buf.getInt().toUInt() != SIGNATURE) {
|
||||
throw InvalidSignatureException("Invalid signature")
|
||||
throw InvalidDataException("Invalid signature")
|
||||
}
|
||||
buf.position(offset + 48)
|
||||
return EndOfCentralDirectoryRecord64(
|
||||
centralDirectoryOffset = buf.getLong().toULong()
|
||||
centralDirectoryOffset = buf.getLong().toULong(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@@ -1,11 +0,0 @@
|
||||
package ziputils
|
||||
|
||||
/**
|
||||
* Represents an invalid raw byte data exception.
|
||||
*/
|
||||
class InvalidDataException(message: String): Exception(message)
|
||||
|
||||
/**
|
||||
* Represents an invalid raw byte signature exception.
|
||||
*/
|
||||
class InvalidSignatureException(message: String): Exception(message)
|
@@ -5,5 +5,5 @@ package ziputils
|
||||
*/
|
||||
internal open class ExtraFieldRecord(
|
||||
val id: UShort,
|
||||
val size: UShort
|
||||
val size: UShort,
|
||||
)
|
6
src/main/kotlin/ziputils/InvalidDataException.kt
Normal file
6
src/main/kotlin/ziputils/InvalidDataException.kt
Normal file
@@ -0,0 +1,6 @@
|
||||
package ziputils
|
||||
|
||||
/**
|
||||
* Represents an invalid raw byte data exception.
|
||||
*/
|
||||
class InvalidDataException(message: String) : Exception(message)
|
@@ -8,8 +8,8 @@ internal class Zip64ExtraFieldRecord(
|
||||
val uncompressedSize: ULong?,
|
||||
val compressedSize: ULong?,
|
||||
val localHeaderOffset: ULong?,
|
||||
val disk: UInt?
|
||||
): ExtraFieldRecord(ID, size) {
|
||||
val disk: UInt?,
|
||||
) : ExtraFieldRecord(ID, size) {
|
||||
companion object {
|
||||
const val ID: UShort = 0x0001U
|
||||
}
|
||||
|
Reference in New Issue
Block a user