Add LZMA compression algorithm

Signed-off-by: Graham <gpe@openrs2.dev>
Graham 4 years ago
parent 29b63b613a
commit f5ae71932d
  1. 1
      buildSrc/src/main/java/Versions.kt
  2. 2
      compress-cli/build.gradle.kts
  3. 6
      compress-cli/src/main/java/dev/openrs2/compress/cli/CompressCommand.kt
  4. 31
      compress-cli/src/main/java/dev/openrs2/compress/cli/lzma/LzmaCommand.kt
  5. 25
      compress-cli/src/main/java/dev/openrs2/compress/cli/lzma/UnlzmaCommand.kt
  6. 5
      compress/build.gradle.kts
  7. 28
      compress/src/main/java/dev/openrs2/compress/lzma/Lzma.kt

@ -24,4 +24,5 @@ object Versions {
const val openrs2Natives = "2.0.1" const val openrs2Natives = "2.0.1"
const val shadowPlugin = "6.0.0" const val shadowPlugin = "6.0.0"
const val versionsPlugin = "0.29.0" const val versionsPlugin = "0.29.0"
const val xz = "1.8"
} }

@ -24,7 +24,7 @@ publishing {
description.set( description.set(
""" """
Tools for compressing and uncompressing headerless bzip2, Tools for compressing and uncompressing headerless bzip2,
DEFLATE and gzip files. DEFLATE, gzip and LZMA files.
""".trimIndent() """.trimIndent()
) )
} }

@ -8,6 +8,8 @@ import dev.openrs2.compress.cli.deflate.DeflateCommand
import dev.openrs2.compress.cli.deflate.InflateCommand import dev.openrs2.compress.cli.deflate.InflateCommand
import dev.openrs2.compress.cli.gzip.GunzipCommand import dev.openrs2.compress.cli.gzip.GunzipCommand
import dev.openrs2.compress.cli.gzip.GzipCommand import dev.openrs2.compress.cli.gzip.GzipCommand
import dev.openrs2.compress.cli.lzma.LzmaCommand
import dev.openrs2.compress.cli.lzma.UnlzmaCommand
fun main(args: Array<String>) = CompressCommand().main(args) fun main(args: Array<String>) = CompressCommand().main(args)
@ -19,7 +21,9 @@ class CompressCommand : NoOpCliktCommand(name = "compress") {
DeflateCommand(), DeflateCommand(),
InflateCommand(), InflateCommand(),
GzipCommand(), GzipCommand(),
GunzipCommand() GunzipCommand(),
LzmaCommand(),
UnlzmaCommand()
) )
} }
} }

@ -0,0 +1,31 @@
package dev.openrs2.compress.cli.lzma
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.default
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.validate
import com.github.ajalt.clikt.parameters.types.defaultStdin
import com.github.ajalt.clikt.parameters.types.defaultStdout
import com.github.ajalt.clikt.parameters.types.inputStream
import com.github.ajalt.clikt.parameters.types.int
import com.github.ajalt.clikt.parameters.types.outputStream
import dev.openrs2.compress.lzma.Lzma
import org.tukaani.xz.LZMA2Options
class LzmaCommand : CliktCommand(name = "lzma") {
private val input by option().inputStream().defaultStdin()
private val output by option().outputStream().defaultStdout()
private val level by option().int().default(LZMA2Options.PRESET_MAX).validate {
require(it >= LZMA2Options.PRESET_MIN && it <= LZMA2Options.PRESET_MAX) {
"--level must be between ${LZMA2Options.PRESET_MIN} and ${LZMA2Options.PRESET_MAX} inclusive"
}
}
override fun run() {
input.use { input ->
Lzma.createHeaderlessOutputStream(output, LZMA2Options(level)).use { output ->
System.err.println(input.copyTo(output))
}
}
}
}

@ -0,0 +1,25 @@
package dev.openrs2.compress.cli.lzma
import com.github.ajalt.clikt.core.CliktCommand
import com.github.ajalt.clikt.parameters.options.option
import com.github.ajalt.clikt.parameters.options.required
import com.github.ajalt.clikt.parameters.types.defaultStdin
import com.github.ajalt.clikt.parameters.types.defaultStdout
import com.github.ajalt.clikt.parameters.types.inputStream
import com.github.ajalt.clikt.parameters.types.long
import com.github.ajalt.clikt.parameters.types.outputStream
import dev.openrs2.compress.lzma.Lzma
class UnlzmaCommand : CliktCommand(name = "unlzma") {
private val input by option().inputStream().defaultStdin()
private val length by option().long().required()
private val output by option().outputStream().defaultStdout()
override fun run() {
Lzma.createHeaderlessInputStream(input, length).use { input ->
output.use { output ->
input.copyTo(output)
}
}
}
}

@ -4,7 +4,10 @@ plugins {
} }
dependencies { dependencies {
api("org.tukaani:xz:${Versions.xz}")
implementation(project(":util")) implementation(project(":util"))
implementation("com.google.guava:guava:${Versions.guava}")
implementation("org.apache.commons:commons-compress:${Versions.commonsCompress}") implementation("org.apache.commons:commons-compress:${Versions.commonsCompress}")
} }
@ -17,7 +20,7 @@ publishing {
name.set("OpenRS2 Compression") name.set("OpenRS2 Compression")
description.set( description.set(
""" """
Provides headerless implementations of bzip2 and gzip. Provides headerless implementations of bzip2, gzip and LZMA.
""".trimIndent() """.trimIndent()
) )
} }

@ -0,0 +1,28 @@
package dev.openrs2.compress.lzma
import com.google.common.io.LittleEndianDataInputStream
import com.google.common.io.LittleEndianDataOutputStream
import org.tukaani.xz.LZMA2Options
import org.tukaani.xz.LZMAInputStream
import org.tukaani.xz.LZMAOutputStream
import java.io.InputStream
import java.io.OutputStream
object Lzma {
fun createHeaderlessInputStream(input: InputStream, length: Long): InputStream {
val headerInput = LittleEndianDataInputStream(input)
val properties = headerInput.readByte()
val dictionarySize = headerInput.readInt()
return LZMAInputStream(input, length, properties, dictionarySize)
}
fun createHeaderlessOutputStream(output: OutputStream, options: LZMA2Options): OutputStream {
val headerOutput = LittleEndianDataOutputStream(output)
headerOutput.writeByte((options.pb * 5 + options.lp) * 9 + options.lc)
headerOutput.writeInt(options.dictSize)
return LZMAOutputStream(output, options, false)
}
}
Loading…
Cancel
Save