6.7.0 - Alpha - 新增 zip 模块 (Ref to Auto.js Pro)

This commit is contained in:
SuperMonster003
2025-06-06 14:30:16 +08:00
parent 78f007b53d
commit 7b00faceb3
5 changed files with 639 additions and 0 deletions

View File

@@ -2,6 +2,9 @@
"$data": {
"v6.7.0": {
"released_date": "2025/06/06",
"feature": [
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))"
],
"fix": [
"版本历史页面部分系统因字体差别导致统计数据显示不完整的问题"
],

View File

@@ -1,6 +1,7 @@
package org.autojs.autojs.extension
import androidx.core.net.toUri
import java.io.File
import java.text.Normalizer
object StringExtensions {
@@ -68,4 +69,10 @@ object StringExtensions {
return true
}
@JvmStatic
fun String.toFile(): File {
val path = this
return File(path)
}
}

View File

@@ -93,6 +93,7 @@ import org.autojs.autojs.runtime.api.augment.util.VersionCodesInfo
import org.autojs.autojs.runtime.api.augment.web.Web
import org.autojs.autojs.runtime.api.augment.web.WebSocket
import org.autojs.autojs.runtime.api.augment.web.WebSocketFields
import org.autojs.autojs.runtime.api.augment.zip.Zip
import org.autojs.autojs.runtime.exception.ScriptEnvironmentException
import org.autojs.autojs.runtime.exception.ScriptException
import org.autojs.autojs.runtime.exception.ScriptInterruptedException
@@ -764,6 +765,7 @@ class ScriptRuntime private constructor(builder: Builder) {
Mime(this).augment(target, mime, true)
SysProps(this).augment(target, true)
SQLite(this).augment(target, true)
Zip(this).augment(target, true)
NanoID.augment(target, true)
Pinyin.augment(target, true)
Pinyin4j.augment(target, true)

View File

@@ -0,0 +1,139 @@
package org.autojs.autojs.runtime.api.augment.zip
import okhttp3.internal.closeQuietly
import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.AnyExtensions.jsBrief
import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.FlexibleArray.Companion.component2
import org.autojs.autojs.extension.FlexibleArray.Companion.component3
import org.autojs.autojs.extension.StringExtensions.toFile
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.Invokable
import org.autojs.autojs.util.RhinoUtils.coerceString
import org.mozilla.javascript.NativeObject
import java.io.File
import java.time.LocalDateTime.now
import java.time.format.DateTimeFormatter.ofPattern
import java.util.UUID.randomUUID
class Zip(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable {
override val key = super.key.lowercase()
override val selfAssignmentFunctions = listOf(
::open.name,
::zipFile.name,
::zipDir.name,
::zipFiles.name,
::unzip.name,
)
override fun invoke(vararg args: Any?): ZipNativeObject = ensureArgumentsOnlyOne(args) { zipPath ->
open(scriptRuntime, arrayOf(zipPath))
}
companion object {
@JvmStatic
@RhinoRuntimeFunctionInterface
fun open(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ZipNativeObject = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val (zipPath, options) = argList
ZipNativeObject(scriptRuntime, ::open.name, zipPath, options)
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun zipFile(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ZipNativeObject = ensureArgumentsLengthInRange(args, 2..3) { argList ->
var (filePath, destZipPath, options) = argList
val fileToZip = scriptRuntime.files.nonNullPath(coerceString(filePath)).toFile()
if (argList.size == 2 && destZipPath is NativeObject) {
options = destZipPath
destZipPath = null
}
val pathString = when {
!destZipPath.isJsNullish() -> coerceString(destZipPath)
else -> "${fileToZip.nameWithoutExtension}.zip"
}
ZipNativeObject(scriptRuntime, ::zipFile.name, pathString, options).tryWithSelf {
zipFile.addFile(fileToZip, zipParameters)
}
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun zipDir(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ZipNativeObject = ensureArgumentsLengthInRange(args, 2..3) { argList ->
var (filePath, destZipPath, options) = argList
val fileToZip = scriptRuntime.files.nonNullPath(coerceString(filePath)).toFile()
if (argList.size == 2 && destZipPath is NativeObject) {
options = destZipPath
destZipPath = null
}
val pathString = when {
!destZipPath.isJsNullish() -> coerceString(destZipPath)
else -> "${fileToZip.nameWithoutExtension}.zip"
}
ZipNativeObject(scriptRuntime, ::zipDir.name, pathString, options).tryWithSelf {
zipFile.createSplitZipFileFromFolder(fileToZip, zipParameters, false, -1)
}
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun zipFiles(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ZipNativeObject = ensureArgumentsLengthInRange(args, 2..3) { argList ->
var (filePathList, destZipPath, options) = argList
require(filePathList is Iterable<*>) {
"Argument filePathList ${filePathList.jsBrief()} for zip.${Companion::zipFiles.name} must be an Iterable"
}
val fileList = mutableListOf<File>()
filePathList.forEach { filePath ->
val file = scriptRuntime.files.nonNullPath(coerceString(filePath)).toFile()
require(file.exists()) {
"File ${file.absolutePath} does not exist"
}
fileList.add(file)
}
if (argList.size == 2 && destZipPath is NativeObject) {
options = destZipPath
destZipPath = null
}
val zipDestinationPath = when {
!destZipPath.isJsNullish() -> coerceString(destZipPath)
fileList.size == 1 -> "${fileList.first().nameWithoutExtension}.zip"
else -> fileList.map {
if (it.isFile) it.parent else it.absolutePath
}.toSet().singleOrNull()?.toFile()?.nameWithoutExtension?.let { "$it.zip" } ?: randomZipName()
}
ZipNativeObject(scriptRuntime, ::zipFiles.name, zipDestinationPath, options).tryWithSelf {
zipFile.addFiles(fileList, zipParameters)
}
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun unzip(scriptRuntime: ScriptRuntime, args: Array<out Any?>): ZipNativeObject = ensureArgumentsLengthInRange(args, 2..3) { argList ->
var (zipPath, destPath, options) = argList
if (argList.size == 2 && destPath is NativeObject) {
options = destPath
destPath = null
}
ZipNativeObject(scriptRuntime, ::unzip.name, zipPath, options).tryWithSelf {
zipFile.extractAll(scriptRuntime.files.nonNullPath(coerceString(destPath, "")), unzipParameters)
}
}
private fun randomZipName(): String {
val ts = now().format(ofPattern("yyyyMMdd-HHmmss"))
val rand = "${randomUUID()}".substring(0, 4).uppercase()
return "${ts}-${rand}.zip"
}
private fun ZipNativeObject.tryWithSelf(func: ZipNativeObject.() -> Unit): ZipNativeObject {
runCatching { func() }.getOrElse { t -> zipFile.closeQuietly(); throw t }
return this
}
}
}

View File

@@ -0,0 +1,488 @@
package org.autojs.autojs.runtime.api.augment.zip
import net.lingala.zip4j.ZipFile
import net.lingala.zip4j.model.ExcludeFileFilter
import net.lingala.zip4j.model.FileHeader
import net.lingala.zip4j.model.UnzipParameters
import net.lingala.zip4j.model.ZipParameters
import net.lingala.zip4j.model.ZipParameters.SymbolicLinkAction
import net.lingala.zip4j.model.enums.AesKeyStrength
import net.lingala.zip4j.model.enums.AesVersion
import net.lingala.zip4j.model.enums.CompressionLevel
import net.lingala.zip4j.model.enums.CompressionMethod
import net.lingala.zip4j.model.enums.EncryptionMethod
import org.autojs.autojs.annotation.RhinoFunctionBody
import org.autojs.autojs.annotation.RhinoStandardFunctionInterface
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.AnyExtensions.isJsNumber
import org.autojs.autojs.extension.AnyExtensions.jsBrief
import org.autojs.autojs.extension.ArrayExtensions.toNativeArray
import org.autojs.autojs.extension.FlexibleArray.Companion.ensureArgumentsIsEmpty
import org.autojs.autojs.extension.FlexibleArray.Companion.ensureArgumentsLengthInRange
import org.autojs.autojs.extension.FlexibleArray.Companion.ensureArgumentsOnlyOne
import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
import org.autojs.autojs.extension.StringExtensions.toFile
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.StringReadable
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils
import org.autojs.autojs.util.RhinoUtils.NOT_CONSTRUCTABLE
import org.autojs.autojs.util.RhinoUtils.callFunction
import org.autojs.autojs.util.RhinoUtils.coerceBoolean
import org.autojs.autojs.util.RhinoUtils.coerceIntNumber
import org.autojs.autojs.util.RhinoUtils.coerceLongNumber
import org.autojs.autojs.util.RhinoUtils.coerceString
import org.autojs.autojs.util.RhinoUtils.coerceStringUppercase
import org.autojs.autojs.util.RhinoUtils.newBaseFunction
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import org.autojs.autojs.util.RhinoUtils.undefined
import org.mozilla.javascript.BaseFunction
import org.mozilla.javascript.Context
import org.mozilla.javascript.Function
import org.mozilla.javascript.NativeArray
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
import org.mozilla.javascript.Undefined
import java.io.File
@Suppress("unused", "UNUSED_PARAMETER")
class ZipNativeObject(
private val scriptRuntime: ScriptRuntime,
private val operationName: String,
rawPath: Any?,
rawOptions: Any? = null,
) : NativeObject(), StringReadable {
@JvmField
val path: String = when {
rawPath.isJsNullish() -> throw WrappedIllegalArgumentException("Argument path ${rawPath.jsBrief()} is invalid for zip.$operationName")
else -> {
val pathString = coerceString(rawPath)
require(pathString.isNotBlank()) {
"Argument path ${pathString.jsBrief()} for zip.$operationName cannot be empty"
}
scriptRuntime.files.nonNullPath(pathString)
}
}
@JvmField
val options: ScriptableObject = when {
rawOptions.isJsNullish() -> newNativeObject()
else -> {
val niceOptions = rawOptions
require(niceOptions is ScriptableObject) {
"Argument options ${niceOptions.jsBrief()} for zip.$operationName must be a JavaScript Object"
}
niceOptions
}
}
private val optionsJavaMap = mutableMapOf<String, Any?>()
@JvmField
val zipFile = ZipFile(path)
@JvmField
val zipParameters: ZipParameters = buildZipParameters(operationName, options)
@JvmField
val unzipParameters: UnzipParameters = buildUnzipParameters(operationName, options)
private val mPropertyNames = arrayOf(
"name" to operationName,
"path" to path,
"zipFile" to zipFile,
"options" to options,
"zipParameters" to zipParameters,
"unzipParameters" to unzipParameters,
)
private val mFunctionNames = arrayOf(
"toString",
::addFile.name,
::addFiles.name,
::addFolder.name,
::extractAll.name,
::extractFile.name,
::setPassword.name,
::getFileHeader.name,
::getFileHeaders.name,
::isEncrypted.name,
::removeFile.name,
::isValidZipFile.name,
::getPath.name,
::getZipFile.name,
)
init {
RhinoUtils.initNativeObjectPrototype(this)
defineFunctionProperties(mFunctionNames, javaClass, PERMANENT)
defineProperty(StringReadable.KEY, newBaseFunction(StringReadable.KEY, { toStringReadable() }, NOT_CONSTRUCTABLE), READONLY or DONTENUM or PERMANENT)
mPropertyNames.forEach { pair ->
val (propertyName, value) = pair
defineProperty(propertyName, value, READONLY or PERMANENT)
}
}
private fun buildZipParameters(funcName: String, opts: Any?): ZipParameters {
val params = ZipParameters()
if (opts.isJsNullish()) {
return params
}
require(opts is ScriptableObject) {
"Argument options ${opts.jsBrief()} for zip.$funcName must be a JavaScript Object"
}
params.aesKeyStrength = opts.inquire("aesKeyStrength", { o, def ->
o.toAesKeyStrength() ?: def
}, AesKeyStrength.KEY_STRENGTH_256).also { optionsJavaMap["aesKeyStrength"] = it }
params.aesVersion = opts.inquire("aesVersion", { o, def ->
o.toAesVersion() ?: def
}, AesVersion.TWO).also { optionsJavaMap["aesVersion"] = it }
params.compressionLevel = opts.inquire("compressionLevel", { o, def ->
o.toCompressionLevel() ?: def
}, CompressionLevel.NORMAL).also { optionsJavaMap["compressionLevel"] = it }
params.compressionMethod = opts.inquire("compressionMethod", { o, def ->
o.toCompressionMethod() ?: def
}, CompressionMethod.DEFLATE).also { optionsJavaMap["compressionMethod"] = it }
params.encryptionMethod = opts.inquire("encryptionMethod", { o, def ->
o.toEncryptionMethod() ?: def
}, EncryptionMethod.AES).also { optionsJavaMap["encryptionMethod"] = it }
opts.inquire("defaultFolderPath", ::coerceString, null)?.let {
params.defaultFolderPath = it.also { optionsJavaMap["defaultFolderPath"] = it }
}
opts.inquire("entryCRC", ::coerceLongNumber, null)?.let {
params.entryCRC = it.also { optionsJavaMap["entryCRC"] = it }
}
opts.inquire("entrySize", ::coerceLongNumber, null)?.let {
params.entrySize = it.also { optionsJavaMap["entrySize"] = it }
}
opts.inquire("excludeFileFilter") { o ->
when {
o.isJsNullish() -> null
o is BaseFunction -> ExcludeFileFilter { file ->
coerceBoolean(callFunction(o, opts, opts, arrayOf(file)), false)
}
o is ExcludeFileFilter -> o
else -> listOf(
"Options property excludeFileFilter ${o.jsBrief()}",
"for zip.$funcName must be a ExcludeFileFilter",
"or a JavaScript Function that can be used as an ExcludeFileFilter",
).joinToString(" ").let { throw WrappedIllegalArgumentException(it) }
}
}?.let {
params.excludeFileFilter = it.also { optionsJavaMap["excludeFileFilter"] = it }
}
opts.inquire(listOf("fileComment", "comment"), ::coerceString, null)?.let {
params.fileComment = it.also {
optionsJavaMap["fileComment"] = it
optionsJavaMap["comment"] = it
}
}
opts.inquire("fileNameInZip", ::coerceString, null)?.let {
params.fileNameInZip = it.also { optionsJavaMap["fileNameInZip"] = it }
}
opts.inquire(listOf("isIncludeRootFolder", "includeRootFolder"), ::coerceBoolean, null)?.let {
params.isIncludeRootFolder = it.also {
optionsJavaMap["isIncludeRootFolder"] = it
optionsJavaMap["includeRootFolder"] = it
}
}
opts.inquire(listOf("isOverrideExistingFilesInZip", "overrideExistingFilesInZip"), ::coerceBoolean, null)?.let {
params.isOverrideExistingFilesInZip = it.also {
optionsJavaMap["isOverrideExistingFilesInZip"] = it
optionsJavaMap["overrideExistingFilesInZip"] = it
}
}
opts.inquire(listOf("isReadHiddenFiles", "readHiddenFiles"), ::coerceBoolean, null)?.let {
params.isReadHiddenFiles = it.also {
optionsJavaMap["isReadHiddenFiles"] = it
optionsJavaMap["readHiddenFiles"] = it
}
}
opts.inquire(listOf("isReadHiddenFolders", "readHiddenFolders"), ::coerceBoolean, null)?.let {
params.isReadHiddenFolders = it.also {
optionsJavaMap["isReadHiddenFolders"] = it
optionsJavaMap["readHiddenFolders"] = it
}
}
opts.inquire(listOf("isUnixMode", "unixMode"), ::coerceBoolean, null)?.let {
params.isUnixMode = it.also {
optionsJavaMap["isUnixMode"] = it
optionsJavaMap["unixMode"] = it
}
}
opts.inquire(listOf("isWriteExtendedLocalFileHeader", "writeExtendedLocalFileHeader"), ::coerceBoolean, null)?.let {
params.isWriteExtendedLocalFileHeader = it.also {
optionsJavaMap["isWriteExtendedLocalFileHeader"] = it
optionsJavaMap["writeExtendedLocalFileHeader"] = it
}
}
opts.inquire("lastModifiedFileTime", ::coerceLongNumber, null)?.let {
params.lastModifiedFileTime = it.also { optionsJavaMap["lastModifiedFileTime"] = it }
}
opts.inquire("rootFolderNameInZip", ::coerceString, null)?.let {
params.rootFolderNameInZip = it.also { optionsJavaMap["rootFolderNameInZip"] = it }
}
params.symbolicLinkAction = opts.inquire("symbolicLinkAction", { o, def ->
o.toSymbolicLinkAction() ?: def
}, SymbolicLinkAction.INCLUDE_LINKED_FILE_ONLY).also { optionsJavaMap["symbolicLinkAction"] = it }
opts.inquire(listOf("isEncryptFiles", "encryptFiles"), ::coerceBoolean, null)?.let {
params.isEncryptFiles = it.also {
optionsJavaMap["isEncryptFiles"] = it
optionsJavaMap["encryptFiles"] = it
}
}
opts.inquire("password") { coerceString(it) }?.let { password ->
zipFile.setPassword(password.toCharArray())
params.isEncryptFiles = true
optionsJavaMap["password"] = password
}
return params
}
private fun buildUnzipParameters(funcName: String, opts: Any?): UnzipParameters {
val params = UnzipParameters()
if (opts.isJsNullish()) {
return params
}
require(opts is ScriptableObject) {
"Argument options ${opts.jsBrief()} for zip.$funcName must be a JavaScript Object"
}
opts.inquire("isExtractSymbolicLinks", ::coerceBoolean, true)
opts.inquire("password") { coerceString(it) }?.let { password ->
zipFile.setPassword(password.toCharArray())
}
opts.inquire(listOf("isIgnoreDateTimeAttributes", "ignoreDateTimeAttributes"), ::coerceBoolean, null)?.let {
throw WrappedIllegalArgumentException("Options property ignoreDateTimeAttributes for zip.$funcName is no longer supported since Zip4j library version 2.x")
}
return params
}
override fun toStringReadable() = toStringRhino(this)
private fun Any.toAesKeyStrength(): AesKeyStrength? = when {
this is AesKeyStrength -> this
this.isJsNullish() -> null
this.isJsNumber() -> AesKeyStrength.entries.find { it.rawCode == coerceIntNumber(this) } ?: when (coerceIntNumber(this)) {
128 -> AesKeyStrength.KEY_STRENGTH_128
192 -> AesKeyStrength.KEY_STRENGTH_192
256 -> AesKeyStrength.KEY_STRENGTH_256
else -> throw WrappedIllegalArgumentException("Options property aesKeyStrength ${this.jsBrief()} is invalid for zip.$operationName")
}
else -> when (val s = coerceStringUppercase(this).removePrefix("AES_STRENGTH_")) {
"128" -> AesKeyStrength.KEY_STRENGTH_128
"192" -> AesKeyStrength.KEY_STRENGTH_192
"256" -> AesKeyStrength.KEY_STRENGTH_256
else -> AesKeyStrength.valueOf(s)
}
}
private fun Any.toAesVersion(): AesVersion? = when {
this is AesVersion -> this
this.isJsNullish() -> null
this.isJsNumber() -> AesVersion.entries.find { it.versionNumber == coerceIntNumber(this) }
else -> when (val s = coerceStringUppercase(this)) {
"1" -> AesVersion.ONE
"2" -> AesVersion.TWO
else -> AesVersion.valueOf(s)
}
}
private fun Any.toCompressionLevel(): CompressionLevel? = when {
this is CompressionLevel -> this
this.isJsNullish() -> null
this.isJsNumber() -> CompressionLevel.entries.find { it.level == coerceIntNumber(this) }
else -> CompressionLevel.valueOf(coerceStringUppercase(this).removePrefix("DEFLATE_LEVEL_"))
}
private fun Any.toCompressionMethod(): CompressionMethod? = when {
this is CompressionMethod -> this
this.isJsNullish() -> null
this.isJsNumber() -> CompressionMethod.entries.find { it.code == coerceIntNumber(this) }
else -> when (val methodName = coerceStringUppercase(this).removePrefix("COMP_")) {
"AES_ENC" -> CompressionMethod.AES_INTERNAL_ONLY
else -> CompressionMethod.valueOf(methodName)
}
}
private fun Any.toEncryptionMethod(): EncryptionMethod? = when {
this is EncryptionMethod -> this
this.isJsNullish() -> null
this.isJsNumber() -> when (coerceIntNumber(this)) {
-1 -> EncryptionMethod.NONE
0 -> EncryptionMethod.ZIP_STANDARD
1 -> EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG
99 -> EncryptionMethod.AES
else -> throw WrappedIllegalArgumentException("Options property encryptionMethod ${this.jsBrief()} is invalid for zip.$operationName")
}
else -> when (val s = coerceStringUppercase(this).removePrefix("ENC_METHOD_").removePrefix("ENC_")) {
"NO_ENCRYPTION", "NO" -> EncryptionMethod.NONE
"STANDARD" -> EncryptionMethod.ZIP_STANDARD
"STRONG" -> EncryptionMethod.ZIP_STANDARD_VARIANT_STRONG
else -> EncryptionMethod.valueOf(s)
}
}
private fun Any.toSymbolicLinkAction(): SymbolicLinkAction? = when {
this is SymbolicLinkAction -> this
this.isJsNullish() -> null
else -> SymbolicLinkAction.valueOf(coerceStringUppercase(this))
}
companion object {
@JvmStatic
@RhinoStandardFunctionInterface
fun toString(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): String = ensureArgumentsIsEmpty(args) {
toStringRhino(thisObj as ZipNativeObject)
}
@JvmStatic
@RhinoFunctionBody
fun toStringRhino(thisObj: ZipNativeObject): String {
val opts = thisObj.options
val optsString: String = when (opts) {
!is NativeObject -> opts.toString()
else -> {
val entries = opts.entries
when {
entries.isEmpty() -> "{}"
else -> "{\n${
entries.joinToString("\n") {
var s = " ${it.key}: ${Context.toString(it.value)}"
if (it.key in thisObj.optionsJavaMap) {
s += " [ ${thisObj.optionsJavaMap[it.key]} ]"
}
"$s,"
}
}\n }"
}
}
}
return listOf(
"${Zip::class.java.simpleName} {",
" operation: ${thisObj.operationName},",
" path: ${thisObj.path},",
" options: $optsString,",
"}",
).joinToString("\n")
}
@JvmStatic
@RhinoStandardFunctionInterface
fun addFile(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val zip = thisObj as ZipNativeObject
val (filePath, options) = argList
val file = zip.scriptRuntime.files.nonNullPath(coerceString(filePath)).toFile()
val zipParameters = zip.buildZipParameters(Companion::addFile.name, options)
undefined { zip.zipFile.addFile(file, zipParameters) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun addFiles(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val zip = thisObj as ZipNativeObject
val (filePathList, options) = argList
require(filePathList is Iterable<*>) {
"Argument filePathList ${filePathList.jsBrief()} for ${ZipNativeObject::class.java.simpleName}#${Companion::addFiles.name} must be an Iterable"
}
val fileList = mutableListOf<File>()
filePathList.forEach { rawFilePath ->
fileList.add(zip.scriptRuntime.files.nonNullPath(coerceString(rawFilePath)).toFile())
}
val zipParameters = zip.buildZipParameters(Companion::addFiles.name, options)
undefined { zip.zipFile.addFiles(fileList, zipParameters) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun addFolder(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val zip = thisObj as ZipNativeObject
val (filePath, options) = argList
val file = zip.scriptRuntime.files.nonNullPath(coerceString(filePath)).toFile()
val zipParameters = zip.buildZipParameters(Companion::addFolder.name, options)
undefined { zip.zipFile.addFolder(file, zipParameters) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun extractAll(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsLengthInRange(args, 1..2) { argList ->
val zip = thisObj as ZipNativeObject
val (rawDestPath, options) = argList
val destPath = zip.scriptRuntime.files.nonNullPath(coerceString(rawDestPath))
val unzipParameters = zip.buildUnzipParameters(Companion::extractAll.name, options)
undefined { zip.zipFile.extractAll(destPath, unzipParameters) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun extractFile(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsLengthInRange(args, 2..4) { argList ->
val zip = thisObj as ZipNativeObject
val (rawZipFilePath, rawDestPath, options, rawNewFileName) = argList
val zipFilePath = zip.scriptRuntime.files.nonNullPath(coerceString(rawZipFilePath))
val destPath = zip.scriptRuntime.files.nonNullPath(coerceString(rawDestPath))
val newFileName = rawNewFileName.takeUnless { it.isJsNullish() }?.let { coerceString(it) }
val unzipParameters = zip.buildUnzipParameters(Companion::extractFile.name, options)
undefined { zip.zipFile.extractFile(zipFilePath, destPath, newFileName, unzipParameters) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun setPassword(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsOnlyOne(args) { password ->
val zip = thisObj as ZipNativeObject
undefined { zip.zipFile.setPassword(coerceString(password).toCharArray()) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun getFileHeader(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): FileHeader = ensureArgumentsOnlyOne(args) { fileName ->
val zip = thisObj as ZipNativeObject
zip.zipFile.getFileHeader(coerceString(fileName))
}
@JvmStatic
@RhinoStandardFunctionInterface
fun getFileHeaders(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): NativeArray = ensureArgumentsIsEmpty(args) {
val zip = thisObj as ZipNativeObject
zip.zipFile.getFileHeaders().toNativeArray()
}
@JvmStatic
@RhinoStandardFunctionInterface
fun isEncrypted(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Boolean = ensureArgumentsIsEmpty(args) {
val zip = thisObj as ZipNativeObject
zip.zipFile.isEncrypted
}
@JvmStatic
@RhinoStandardFunctionInterface
fun removeFile(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Undefined = ensureArgumentsOnlyOne(args) { fileName ->
val zip = thisObj as ZipNativeObject
undefined { zip.zipFile.removeFile(coerceString(fileName)) }
}
@JvmStatic
@RhinoStandardFunctionInterface
fun isValidZipFile(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): Boolean = ensureArgumentsIsEmpty(args) {
val zip = thisObj as ZipNativeObject
zip.zipFile.isValidZipFile
}
@JvmStatic
@RhinoStandardFunctionInterface
fun getPath(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): String = ensureArgumentsIsEmpty(args) {
val zip = thisObj as ZipNativeObject
zip.path
}
@JvmStatic
@RhinoStandardFunctionInterface
fun getZipFile(cx: Context, thisObj: Scriptable, args: Array<Any?>, funObj: Function): ZipFile = ensureArgumentsIsEmpty(args) {
val zip = thisObj as ZipNativeObject
zip.zipFile
}
}
}