This commit is contained in:
kunfei 2023-04-21 23:44:32 +08:00
parent e70743878a
commit 359675f92d
15 changed files with 100 additions and 316 deletions

View File

@ -1,7 +1,7 @@
package io.legado.app package io.legado.app
import io.legado.app.rhino.Rhino import com.script.SimpleBindings
import io.legado.app.rhino.putBinding import com.script.rhino.RhinoScriptEngine
import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.Language
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
@ -36,17 +36,13 @@ class AndroidJsTest {
var queryStringWithSign = "Signature=" + signStr + "&" + query; var queryStringWithSign = "Signature=" + signStr + "&" + query;
queryStringWithSign queryStringWithSign
""".trimIndent() """.trimIndent()
Rhino.use { RhinoScriptEngine.eval(js)
evaluateString(it, js, "yy", 1, null)
}
@Language("js") @Language("js")
val js1 = """ val js1 = """
var returnData = new Packages.io.legado.app.api.ReturnData() var returnData = new Packages.io.legado.app.api.ReturnData()
returnData.getErrorMsg() returnData.getErrorMsg()
""".trimIndent() """.trimIndent()
val result1 = Rhino.use { val result1 = RhinoScriptEngine.eval(js1)
evaluateString(it, js1, "xx", 1, null)
}
Assert.assertEquals(result1, "未知错误,请联系开发者!").let { Assert.assertEquals(result1, "未知错误,请联系开发者!").let {
} }
@ -55,20 +51,15 @@ class AndroidJsTest {
@Test @Test
fun testMap() { fun testMap() {
val map = hashMapOf("id" to "3242532321") val map = hashMapOf("id" to "3242532321")
val bindings = SimpleBindings()
bindings["result"] = map
@Language("js") @Language("js")
val jsMap = "$=result;id=$.id;id" val jsMap = "$=result;id=$.id;id"
val result = Rhino.use { val result = RhinoScriptEngine.eval(jsMap, bindings)
it.putBinding("result", map)
evaluateString(it, jsMap, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result) Assert.assertEquals("3242532321", result)
@Language("js") @Language("js")
val jsMap1 = """result.get("id")""" val jsMap1 = """result.get("id")"""
val result1 = Rhino.use { val result1 = RhinoScriptEngine.eval(jsMap1, bindings)
it.putBinding("result", map)
evaluateString(it, jsMap1, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result1) Assert.assertEquals("3242532321", result1)
} }

View File

@ -11,7 +11,6 @@ import io.legado.app.help.JsExtensions
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.http.CookieStore import io.legado.app.help.http.CookieStore
import io.legado.app.model.SharedJsScope import io.legado.app.model.SharedJsScope
import io.legado.app.rhino.Bindings
import io.legado.app.utils.* import io.legado.app.utils.*
import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.Language
import org.mozilla.javascript.Scriptable import org.mozilla.javascript.Scriptable
@ -228,22 +227,15 @@ interface BaseSource : JsExtensions {
* 执行JS * 执行JS
*/ */
@Throws(Exception::class) @Throws(Exception::class)
fun evalJS(jsStr: String, bindingsConfig: Bindings.() -> Unit = {}): Any? { fun evalJS(jsStr: String, bindingsConfig: SimpleBindings.() -> Unit = {}): Any? {
val bindings = Bindings() val bindings = SimpleBindings()
bindings.apply(bindingsConfig) bindings.apply(bindingsConfig)
bindings["java"] = this bindings["java"] = this
bindings["source"] = this bindings["source"] = this
bindings["baseUrl"] = getKey() bindings["baseUrl"] = getKey()
bindings["cookie"] = CookieStore bindings["cookie"] = CookieStore
bindings["cache"] = CacheManager bindings["cache"] = CacheManager
// return Rhino.use { scope -> val context = RhinoScriptEngine.getScriptContext(bindings)
// scope.putBindings(bindings)
// getShareScope()?.let {
// scope.prototype = it
// }
// eval(scope, jsStr)
// }
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context) val scope = RhinoScriptEngine.getRuntimeScope(context)
getShareScope()?.let { getShareScope()?.let {
scope.prototype = it scope.prototype = it

View File

@ -3,6 +3,8 @@
package io.legado.app.help.book package io.legado.app.help.book
import android.net.Uri import android.net.Uri
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.constant.* import io.legado.app.constant.*
import io.legado.app.data.appDb import io.legado.app.data.appDb
import io.legado.app.data.entities.BaseBook import io.legado.app.data.entities.BaseBook
@ -10,9 +12,6 @@ import io.legado.app.data.entities.Book
import io.legado.app.data.entities.BookSource import io.legado.app.data.entities.BookSource
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.rhino.Bindings
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.putBindings
import io.legado.app.utils.* import io.legado.app.utils.*
import splitties.init.appCtx import splitties.init.appCtx
import java.io.File import java.io.File
@ -236,14 +235,11 @@ fun Book.getExportFileName(suffix: String): String {
if (jsStr.isNullOrBlank()) { if (jsStr.isNullOrBlank()) {
return "$name 作者:${getRealAuthor()}.$suffix" return "$name 作者:${getRealAuthor()}.$suffix"
} }
val bindings = Bindings() val bindings = SimpleBindings()
bindings["name"] = name bindings["name"] = name
bindings["author"] = getRealAuthor() bindings["author"] = getRealAuthor()
return kotlin.runCatching { return kotlin.runCatching {
Rhino.use { RhinoScriptEngine.eval(jsStr, bindings).toString() + "." + suffix
it.putBindings(bindings)
evaluateString(it, jsStr, "name&author", 1, null)
}.toString() + "." + suffix
}.onFailure { }.onFailure {
AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it) AppLog.put("导出书名规则错误,使用默认规则\n${it.localizedMessage}", it)
}.getOrDefault("${name} 作者:${getRealAuthor()}.$suffix") }.getOrDefault("${name} 作者:${getRealAuthor()}.$suffix")

View File

@ -109,10 +109,14 @@ object Backup {
writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath) writeListToJson(appDb.httpTTSDao.all, "httpTTS.json", backupPath)
writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath) writeListToJson(appDb.keyboardAssistsDao.all, "keyboardAssists.json", backupPath)
writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath) writeListToJson(appDb.dictRuleDao.all, "dictRule.json", backupPath)
aes.encryptBase64(GSON.toJson(appDb.serverDao.all)).let { GSON.toJson(appDb.serverDao.all).let { json ->
aes.runCatching {
encryptBase64(json)
}.getOrDefault(json).let {
FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json") FileUtils.createFileIfNotExist(backupPath + File.separator + "servers.json")
.writeText(it) .writeText(it)
} }
}
ensureActive() ensureActive()
GSON.toJson(ReadBookConfig.configList).let { GSON.toJson(ReadBookConfig.configList).let {
FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName) FileUtils.createFileIfNotExist(backupPath + File.separator + ReadBookConfig.configFileName)
@ -137,7 +141,9 @@ object Backup {
if (BackupConfig.keyIsNotIgnore(key)) { if (BackupConfig.keyIsNotIgnore(key)) {
when (key) { when (key) {
PreferKey.webDavPassword -> { PreferKey.webDavPassword -> {
edit.putString(key, aes.encryptBase64(value.toString())) edit.putString(key, aes.runCatching {
encryptBase64(value.toString())
}.getOrDefault(value.toString()))
} }
else -> when (value) { else -> when (value) {

View File

@ -1,10 +1,11 @@
package io.legado.app.model package io.legado.app.model
import com.google.gson.reflect.TypeToken import com.google.gson.reflect.TypeToken
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.exception.NoStackTraceException import io.legado.app.exception.NoStackTraceException
import io.legado.app.help.http.newCallStrResponse import io.legado.app.help.http.newCallStrResponse
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import io.legado.app.rhino.Rhino
import io.legado.app.utils.ACache import io.legado.app.utils.ACache
import io.legado.app.utils.GSON import io.legado.app.utils.GSON
import io.legado.app.utils.MD5Utils import io.legado.app.utils.MD5Utils
@ -31,8 +32,9 @@ object SharedJsScope {
val key = MD5Utils.md5Encode(jsLib) val key = MD5Utils.md5Encode(jsLib)
var scope = scopeMap[key]?.get() var scope = scopeMap[key]?.get()
if (scope == null) { if (scope == null) {
Rhino.use { scope = RhinoScriptEngine.run {
scope = it getRuntimeScope(getScriptContext(SimpleBindings()))
}
if (jsLib.isJsonObject()) { if (jsLib.isJsonObject()) {
val jsMap: Map<String, String> = GSON.fromJson( val jsMap: Map<String, String> = GSON.fromJson(
jsLib, jsLib,
@ -58,12 +60,11 @@ object SharedJsScope {
throw NoStackTraceException("下载jsLib-${value}失败") throw NoStackTraceException("下载jsLib-${value}失败")
} }
} }
evaluateString(scope, js, "jsLib", 1, null) RhinoScriptEngine.eval(js, scope)
} }
} }
} else { } else {
evaluateString(scope, jsLib, "jsLib", 1, null) RhinoScriptEngine.eval(jsLib, scope)
}
} }
scopeMap[key] = WeakReference(scope) scopeMap[key] = WeakReference(scope)
} }

View File

@ -10,7 +10,6 @@ import io.legado.app.help.CacheManager
import io.legado.app.help.JsExtensions import io.legado.app.help.JsExtensions
import io.legado.app.help.http.CookieStore import io.legado.app.help.http.CookieStore
import io.legado.app.model.webBook.WebBook import io.legado.app.model.webBook.WebBook
import io.legado.app.rhino.Bindings
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withTimeout import kotlinx.coroutines.withTimeout
@ -698,7 +697,7 @@ class AnalyzeRule(
* 执行JS * 执行JS
*/ */
fun evalJS(jsStr: String, result: Any? = null): Any? { fun evalJS(jsStr: String, result: Any? = null): Any? {
val bindings = Bindings() val bindings = SimpleBindings()
bindings["java"] = this bindings["java"] = this
bindings["cookie"] = CookieStore bindings["cookie"] = CookieStore
bindings["cache"] = CacheManager bindings["cache"] = CacheManager
@ -710,14 +709,7 @@ class AnalyzeRule(
bindings["title"] = chapter?.title bindings["title"] = chapter?.title
bindings["src"] = content bindings["src"] = content
bindings["nextChapterUrl"] = nextChapterUrl bindings["nextChapterUrl"] = nextChapterUrl
// return Rhino.use { scope -> val context = RhinoScriptEngine.getScriptContext(bindings)
// scope.putBindings(bindings)
// source?.getShareScope()?.let {
// scope.prototype = it
// }
// eval(scope, jsStr)
// }
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context) val scope = RhinoScriptEngine.getRuntimeScope(context)
source?.getShareScope()?.let { source?.getShareScope()?.let {
scope.prototype = it scope.prototype = it

View File

@ -20,7 +20,6 @@ import io.legado.app.help.JsExtensions
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.glide.GlideHeaders import io.legado.app.help.glide.GlideHeaders
import io.legado.app.help.http.* import io.legado.app.help.http.*
import io.legado.app.rhino.Bindings
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
@ -255,7 +254,7 @@ class AnalyzeUrl(
* 执行JS * 执行JS
*/ */
fun evalJS(jsStr: String, result: Any? = null): Any? { fun evalJS(jsStr: String, result: Any? = null): Any? {
val bindings = Bindings() val bindings = SimpleBindings()
bindings["java"] = this bindings["java"] = this
bindings["baseUrl"] = baseUrl bindings["baseUrl"] = baseUrl
bindings["cookie"] = CookieStore bindings["cookie"] = CookieStore
@ -267,14 +266,7 @@ class AnalyzeUrl(
bindings["book"] = ruleData as? Book bindings["book"] = ruleData as? Book
bindings["source"] = source bindings["source"] = source
bindings["result"] = result bindings["result"] = result
// return Rhino.use { scope -> val context = RhinoScriptEngine.getScriptContext(bindings)
// scope.putBindings(bindings)
// source?.getShareScope()?.let {
// scope.prototype = it
// }
// eval(scope, jsStr)
// }
val context = RhinoScriptEngine.getScriptContext(SimpleBindings(bindings))
val scope = RhinoScriptEngine.getRuntimeScope(context) val scope = RhinoScriptEngine.getRuntimeScope(context)
source?.getShareScope()?.let { source?.getShareScope()?.let {
scope.prototype = it scope.prototype = it

View File

@ -3,6 +3,8 @@ package io.legado.app.model.localBook
import android.net.Uri import android.net.Uri
import android.util.Base64 import android.util.Base64
import androidx.documentfile.provider.DocumentFile import androidx.documentfile.provider.DocumentFile
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.R import io.legado.app.R
import io.legado.app.constant.* import io.legado.app.constant.*
import io.legado.app.data.appDb import io.legado.app.data.appDb
@ -19,9 +21,6 @@ import io.legado.app.help.config.AppConfig
import io.legado.app.lib.webdav.WebDav import io.legado.app.lib.webdav.WebDav
import io.legado.app.lib.webdav.WebDavException import io.legado.app.lib.webdav.WebDavException
import io.legado.app.model.analyzeRule.AnalyzeUrl import io.legado.app.model.analyzeRule.AnalyzeUrl
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import io.legado.app.utils.* import io.legado.app.utils.*
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import org.jsoup.nodes.Entities import org.jsoup.nodes.Entities
@ -271,9 +270,10 @@ object LocalBook {
val js = val js =
AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})" AppConfig.bookImportFileName + "\nJSON.stringify({author:author,name:name})"
//在脚本中定义如何分解文件名成书名、作者名 //在脚本中定义如何分解文件名成书名、作者名
val jsonStr = Rhino.use { val jsonStr = RhinoScriptEngine.run {
it.putBinding("src", tempFileName) val bindings = SimpleBindings()
eval(it, js) bindings["src"] = tempFileName
eval(js, bindings)
}.toString() }.toString()
val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr) val bookMess = GSON.fromJsonObject<HashMap<String, String>>(jsonStr)
.getOrThrow() .getOrThrow()

View File

@ -1,54 +0,0 @@
/*
* Decompiled with CFR 0.152.
*/
package io.legado.app.rhino
class Bindings @JvmOverloads constructor(
private val map: MutableMap<String, Any?> = HashMap()
) : MutableMap<String, Any?> {
override fun put(key: String, value: Any?): Any? {
return map.put(key, value)
}
override fun putAll(from: Map<out String, Any?>) {
map.putAll(from)
}
override fun clear() {
map.clear()
}
override fun containsKey(key: String): Boolean {
return map.containsKey(key)
}
override fun containsValue(value: Any?): Boolean {
return map.containsValue(value)
}
override val entries: MutableSet<MutableMap.MutableEntry<String, Any?>>
get() = map.entries
override operator fun get(key: String): Any? {
return map[key]
}
override fun isEmpty(): Boolean {
return map.isEmpty()
}
override val keys: MutableSet<String>
get() = map.keys
override fun remove(key: String): Any? {
return map.remove(key)
}
override val size: Int
get() = map.size
override val values: MutableCollection<Any?>
get() = map.values
}

View File

@ -1,43 +0,0 @@
package io.legado.app.rhino
import org.mozilla.javascript.Context
import org.mozilla.javascript.ImporterTopLevel
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.Undefined
import org.mozilla.javascript.Wrapper
object Rhino {
inline fun <T> use(block: Context.(Scriptable) -> T): T {
return try {
val cx = Context.enter()
val scope = cx.initStandardObjects(ImporterTopLevel(cx))
block.invoke(cx, scope)
} finally {
Context.exit()
}
}
fun unwrapReturnValue(result: Any?): Any? {
var result1 = result
if (result1 is Wrapper) {
result1 = result1.unwrap()
}
return if (result1 is Undefined) null else result1
}
// init {
// ContextFactory.initGlobal(object : RhinoContextFactory() {
//
// override fun makeContext(): Context {
// val cx = super.makeContext()
// cx.languageVersion = 200
// cx.optimizationLevel = -1
// cx.setClassShutter(RhinoClassShutter)
// return cx
// }
//
// })
// }
}

View File

@ -1,62 +0,0 @@
/*
* Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package io.legado.app.rhino
import org.mozilla.javascript.ClassShutter
/**
* This class prevents script access to certain sensitive classes.
* Note that this class checks over and above SecurityManager. i.e., although
* a SecurityManager would pass, class shutter may still prevent access.
*
* @author A. Sundararajan
* @since 1.6
*/
object RhinoClassShutter : ClassShutter {
private val protectedClasses by lazy {
val protectedClasses = HashMap<Any, Any>()
protectedClasses["java.lang.Runtime"] = java.lang.Boolean.TRUE
protectedClasses["java.io.File"] = java.lang.Boolean.TRUE
protectedClasses["java.security.AccessController"] = java.lang.Boolean.TRUE
protectedClasses
}
override fun visibleToScripts(fullClassName: String): Boolean {
val sm = System.getSecurityManager()
if (sm != null) {
val i = fullClassName.lastIndexOf(".")
if (i != -1) {
try {
sm.checkPackageAccess(fullClassName.substring(0, i))
} catch (e: SecurityException) {
return false
}
}
}
return protectedClasses[fullClassName] == null
}
}

View File

@ -2,6 +2,7 @@
package io.legado.app.rhino package io.legado.app.rhino
import com.script.Bindings
import org.mozilla.javascript.Context import org.mozilla.javascript.Context
import org.mozilla.javascript.Scriptable import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject import org.mozilla.javascript.ScriptableObject
@ -14,9 +15,7 @@ fun Context.eval(
lineno: Int = 1, lineno: Int = 1,
securityDomain: Any? = null securityDomain: Any? = null
): Any? { ): Any? {
return Rhino.unwrapReturnValue( return evaluateString(scope, source, sourceName, lineno, securityDomain)
evaluateString(scope, source, sourceName, lineno, securityDomain)
)
} }
fun Context.eval( fun Context.eval(
@ -26,9 +25,7 @@ fun Context.eval(
lineno: Int = 1, lineno: Int = 1,
securityDomain: Any? = null securityDomain: Any? = null
): Any? { ): Any? {
return Rhino.unwrapReturnValue( return evaluateReader(scope, reader, sourceName, lineno, securityDomain)
evaluateReader(scope, reader, sourceName, lineno, securityDomain)
)
} }
fun Scriptable.putBinding(key: String, value: Any?) { fun Scriptable.putBinding(key: String, value: Any?) {

View File

@ -1,25 +1,20 @@
package io.legado.app.utils package io.legado.app.utils
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.constant.AppPattern.EXP_PATTERN import io.legado.app.constant.AppPattern.EXP_PATTERN
import io.legado.app.rhino.Bindings
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBindings
object JsUtils { object JsUtils {
fun evalJs(js: String, bindingsFun: ((Bindings) -> Unit)? = null): String { fun evalJs(js: String, bindingsFun: ((SimpleBindings) -> Unit)? = null): String {
val bindings = Bindings() val bindings = SimpleBindings()
bindingsFun?.invoke(bindings) bindingsFun?.invoke(bindings)
if (js.contains("{{") && js.contains("}}")) { if (js.contains("{{") && js.contains("}}")) {
val sb = StringBuffer() val sb = StringBuffer()
val expMatcher = EXP_PATTERN.matcher(js) val expMatcher = EXP_PATTERN.matcher(js)
while (expMatcher.find()) { while (expMatcher.find()) {
val result = expMatcher.group(1)?.let { js1 -> val result = expMatcher.group(1)?.let { js1 ->
Rhino.use { RhinoScriptEngine.eval(js1, bindings)
it.putBindings(bindings)
eval(it, js1)
}
} ?: "" } ?: ""
if (result is String) { if (result is String) {
expMatcher.appendReplacement(sb, result) expMatcher.appendReplacement(sb, result)
@ -32,10 +27,7 @@ object JsUtils {
expMatcher.appendTail(sb) expMatcher.appendTail(sb)
return sb.toString() return sb.toString()
} }
return Rhino.use { return RhinoScriptEngine.eval(js, bindings).toString()
it.putBindings(bindings)
eval(it, js)
}.toString()
} }

View File

@ -1,12 +1,11 @@
package io.legado.app.utils package io.legado.app.utils
import androidx.core.os.postDelayed import androidx.core.os.postDelayed
import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.exception.RegexTimeoutException import io.legado.app.exception.RegexTimeoutException
import io.legado.app.help.CrashHandler import io.legado.app.help.CrashHandler
import io.legado.app.help.coroutine.Coroutine import io.legado.app.help.coroutine.Coroutine
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.suspendCancellableCoroutine
import splitties.init.appCtx import splitties.init.appCtx
@ -31,9 +30,10 @@ fun CharSequence.replace(regex: Regex, replacement: String, timeout: Long): Stri
val stringBuffer = StringBuffer() val stringBuffer = StringBuffer()
while (matcher.find()) { while (matcher.find()) {
if (isJs) { if (isJs) {
val jsResult = Rhino.use { val jsResult = RhinoScriptEngine.run {
it.putBinding("result", matcher.group()) val bindings = SimpleBindings()
eval(it, replacement1) bindings["result"] = matcher.group()
eval(replacement1, bindings)
}.toString() }.toString()
matcher.appendReplacement(stringBuffer, jsResult) matcher.appendReplacement(stringBuffer, jsResult)
} else { } else {

View File

@ -1,10 +1,8 @@
package io.legado.app package io.legado.app
import com.script.SimpleBindings import com.script.SimpleBindings
import com.script.rhino.RhinoScriptEngine
import io.legado.app.data.entities.BookChapter import io.legado.app.data.entities.BookChapter
import io.legado.app.rhino.Rhino
import io.legado.app.rhino.eval
import io.legado.app.rhino.putBinding
import org.intellij.lang.annotations.Language import org.intellij.lang.annotations.Language
import org.junit.Assert import org.junit.Assert
import org.junit.Test import org.junit.Test
@ -30,29 +28,24 @@ class JsTest {
@Test @Test
fun testMap() { fun testMap() {
val map = hashMapOf("id" to "3242532321") val map = hashMapOf("id" to "3242532321")
val bindings = SimpleBindings()
bindings["result"] = map
@Language("js") @Language("js")
val jsMap = "$=result;id=$.id;id" val jsMap = "$=result;id=$.id;id"
val result = Rhino.use { val result = RhinoScriptEngine.eval(jsMap, bindings)
val scope = initStandardObjects()
scope.putBinding("result", map)
evaluateString(scope, jsMap, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result) Assert.assertEquals("3242532321", result)
@Language("js") @Language("js")
val jsMap1 = """result.get("id")""" val jsMap1 = """result.get("id")"""
val result1 = Rhino.use { val result1 = RhinoScriptEngine.eval(jsMap1, bindings)
it.putBinding("result", map)
evaluateString(it, jsMap1, "xxx", 1, null)
}
Assert.assertEquals("3242532321", result1) Assert.assertEquals("3242532321", result1)
} }
@Test @Test
fun testFor() { fun testFor() {
val scope = Rhino.use { val scope = RhinoScriptEngine.run {
evaluateString(it, printJs, "print", 1, null) val scope = getRuntimeScope(getScriptContext(SimpleBindings()))
it eval(printJs, scope)
scope
} }
@Language("js") @Language("js")
@ -74,18 +67,13 @@ class JsTest {
} }
result result
""".trimIndent() """.trimIndent()
val result = Rhino.use { val result = RhinoScriptEngine.eval(jsFor, scope)
it.prototype = scope
evaluateString(it, jsFor, "jsFor", 1, null)
}
Assert.assertEquals("12012", result) Assert.assertEquals("12012", result)
} }
@Test @Test
fun testReturnNull() { fun testReturnNull() {
val result = Rhino.use { val result = RhinoScriptEngine.eval("null")
eval(it, "null")
}
Assert.assertEquals(null, result) Assert.assertEquals(null, result)
} }
@ -101,9 +89,10 @@ class JsTest {
.replace(/\;/g,"") .replace(/\;/g,"")
.replace(/\:/g,"") .replace(/\:/g,"")
""".trimIndent() """.trimIndent()
val result = Rhino.use { val result = RhinoScriptEngine.run {
it.putBinding("result", ",.!?…;:") val bindings = SimpleBindings()
eval(it, js) bindings["result"] = ",.!?…;:"
eval(js)
} }
Assert.assertEquals(result, ",。!?……;:") Assert.assertEquals(result, ",。!?……;:")
} }
@ -116,27 +105,22 @@ class JsTest {
bindings["chapter"] = chapter bindings["chapter"] = chapter
@Language("js") @Language("js")
val js = "chapter.title" val js = "chapter.title"
val result = Rhino.use { val result = RhinoScriptEngine.eval(js, bindings)
it.putBinding("chapter", chapter)
eval(it, js)
}
Assert.assertEquals(result, "xxxyyy") Assert.assertEquals(result, "xxxyyy")
} }
@Test @Test
fun javaListForEach() { fun javaListForEach() {
val list = arrayListOf(1, 2, 3) val list = arrayListOf(1, 2, 3)
val bindings = SimpleBindings()
bindings["list"] = list
@Language("js") @Language("js")
val js = """ val js = """
var result = 0 var result = 0
list.forEach(item => {result = result + item}) list.forEach(item => {result = result + item})
result result
""".trimIndent() """.trimIndent()
val result = Rhino.use { val result = RhinoScriptEngine.eval(js, bindings)
it.putBinding("list", list)
eval(it, js)
}
Assert.assertEquals(result, 6.0) Assert.assertEquals(result, 6.0)
} }