mirror of
https://github.com/gedoor/legado.git
synced 2025-08-10 00:52:30 +00:00
316 lines
11 KiB
Kotlin
316 lines
11 KiB
Kotlin
/*
|
|
* Copyright (c) 2005, 2011, 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 com.script.rhino
|
|
|
|
import com.script.*
|
|
import org.mozilla.javascript.*
|
|
import org.mozilla.javascript.Function
|
|
import java.io.IOException
|
|
import java.io.Reader
|
|
import java.io.StringReader
|
|
import java.lang.reflect.Method
|
|
import java.security.*
|
|
|
|
/**
|
|
* Implementation of `ScriptEngine` using the Mozilla Rhino
|
|
* interpreter.
|
|
*
|
|
* @author Mike Grogan
|
|
* @author A. Sundararajan
|
|
* @since 1.6
|
|
*/
|
|
@Suppress("MemberVisibilityCanBePrivate")
|
|
object RhinoScriptEngine : AbstractScriptEngine(), Invocable, Compilable {
|
|
var accessContext: AccessControlContext? = null
|
|
private var topLevel: RhinoTopLevel? = null
|
|
private val indexedProps: MutableMap<Any, Any?>
|
|
private val implementor: InterfaceImplementor
|
|
|
|
fun eval(js: String, bindingsConfig: SimpleBindings.() -> Unit = {}): Any? {
|
|
val bindings = SimpleBindings()
|
|
bindings.apply(bindingsConfig)
|
|
return eval(js, bindings)
|
|
}
|
|
|
|
@Throws(ScriptException::class)
|
|
override fun eval(reader: Reader, scope: Scriptable): Any? {
|
|
val cx = Context.enter()
|
|
val ret: Any?
|
|
try {
|
|
var filename = this["javax.script.filename"] as? String
|
|
filename = filename ?: "<Unknown source>"
|
|
ret = cx.evaluateReader(scope, reader, filename, 1, null)
|
|
} catch (re: RhinoException) {
|
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
|
val msg: String = if (re is JavaScriptException) {
|
|
re.value.toString()
|
|
} else {
|
|
re.toString()
|
|
}
|
|
val se = ScriptException(msg, re.sourceName(), line)
|
|
se.initCause(re)
|
|
throw se
|
|
} catch (var14: IOException) {
|
|
throw ScriptException(var14)
|
|
} finally {
|
|
Context.exit()
|
|
}
|
|
return unwrapReturnValue(ret)
|
|
}
|
|
|
|
override fun createBindings(): Bindings {
|
|
return SimpleBindings()
|
|
}
|
|
|
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
|
override fun invokeFunction(name: String, vararg args: Any): Any? {
|
|
return this.invoke(null, name, *args)
|
|
}
|
|
|
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
|
override fun invokeMethod(obj: Any?, name: String, vararg args: Any): Any? {
|
|
return if (obj == null) {
|
|
throw IllegalArgumentException("脚本对象不能为空")
|
|
} else {
|
|
this.invoke(obj, name, *args)
|
|
}
|
|
}
|
|
|
|
@Suppress("UNCHECKED_CAST")
|
|
@Throws(ScriptException::class, NoSuchMethodException::class)
|
|
private operator fun invoke(thiz: Any?, name: String?, vararg args: Any?): Any? {
|
|
var thiz1 = thiz
|
|
val cx = Context.enter()
|
|
val var11: Any?
|
|
try {
|
|
if (name == null) {
|
|
throw NullPointerException("方法名为空")
|
|
}
|
|
if (thiz1 != null && thiz1 !is Scriptable) {
|
|
thiz1 = Context.toObject(thiz1, topLevel)
|
|
}
|
|
val engineScope = getRuntimeScope(context)
|
|
val localScope = if (thiz1 != null) thiz1 as Scriptable else engineScope
|
|
val obj = ScriptableObject.getProperty(localScope, name) as? Function
|
|
?: throw NoSuchMethodException("no such method: $name")
|
|
var scope = obj.parentScope
|
|
if (scope == null) {
|
|
scope = engineScope
|
|
}
|
|
val result = obj.call(cx, scope, localScope, wrapArguments(args as? Array<Any?>))
|
|
var11 = unwrapReturnValue(result)
|
|
} catch (re: RhinoException) {
|
|
val line = if (re.lineNumber() == 0) -1 else re.lineNumber()
|
|
val se = ScriptException(re.toString(), re.sourceName(), line)
|
|
se.initCause(re)
|
|
throw se
|
|
} finally {
|
|
Context.exit()
|
|
}
|
|
return var11
|
|
}
|
|
|
|
override fun <T> getInterface(clazz: Class<T>): T? {
|
|
return try {
|
|
implementor.getInterface(null, clazz)
|
|
} catch (var3: ScriptException) {
|
|
null
|
|
}
|
|
}
|
|
|
|
override fun <T> getInterface(obj: Any?, paramClass: Class<T>): T? {
|
|
return if (obj == null) {
|
|
throw IllegalArgumentException("脚本对象不能为空")
|
|
} else {
|
|
try {
|
|
implementor.getInterface(obj, paramClass)
|
|
} catch (var4: ScriptException) {
|
|
null
|
|
}
|
|
}
|
|
}
|
|
|
|
override fun getRuntimeScope(context: ScriptContext): Scriptable {
|
|
val newScope: Scriptable = ExternalScriptable(context, indexedProps)
|
|
newScope.prototype = topLevel
|
|
newScope.put("context", newScope, context)
|
|
return newScope
|
|
}
|
|
|
|
@Throws(ScriptException::class)
|
|
override fun compile(script: String): CompiledScript {
|
|
return this.compile(StringReader(script) as Reader)
|
|
}
|
|
|
|
@Throws(ScriptException::class)
|
|
override fun compile(script: Reader): CompiledScript {
|
|
val cx = Context.enter()
|
|
val ret: RhinoCompiledScript
|
|
try {
|
|
var fileName = this["javax.script.filename"] as? String
|
|
if (fileName == null) {
|
|
fileName = "<Unknown Source>"
|
|
}
|
|
val scr = cx.compileReader(script, fileName, 1, null)
|
|
ret = RhinoCompiledScript(this, scr)
|
|
} catch (var9: Exception) {
|
|
throw ScriptException(var9)
|
|
} finally {
|
|
Context.exit()
|
|
}
|
|
return ret
|
|
}
|
|
|
|
fun wrapArguments(args: Array<Any?>?): Array<Any?> {
|
|
return if (args == null) {
|
|
Context.emptyArgs
|
|
} else {
|
|
val res = arrayOfNulls<Any>(args.size)
|
|
for (i in res.indices) {
|
|
res[i] = Context.javaToJS(args[i], topLevel)
|
|
}
|
|
res
|
|
}
|
|
}
|
|
|
|
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 : ContextFactory() {
|
|
|
|
override fun makeContext(): Context {
|
|
val cx = super.makeContext()
|
|
cx.languageVersion = 200
|
|
cx.optimizationLevel = -1
|
|
cx.setClassShutter(RhinoClassShutter)
|
|
cx.wrapFactory = RhinoWrapFactory
|
|
return cx
|
|
}
|
|
|
|
override fun hasFeature(cx: Context, featureIndex: Int): Boolean {
|
|
@Suppress("UNUSED_EXPRESSION")
|
|
return when (featureIndex) {
|
|
//Context.FEATURE_ENABLE_JAVA_MAP_ACCESS -> true
|
|
else -> super.hasFeature(cx, featureIndex)
|
|
}
|
|
}
|
|
|
|
override fun doTopCall(
|
|
callable: Callable,
|
|
cx: Context,
|
|
scope: Scriptable,
|
|
thisObj: Scriptable,
|
|
args: Array<Any>
|
|
): Any? {
|
|
var accContext: AccessControlContext? = null
|
|
val global = ScriptableObject.getTopLevelScope(scope)
|
|
val globalProto = global.prototype
|
|
if (globalProto is RhinoTopLevel) {
|
|
accContext = globalProto.accessContext
|
|
}
|
|
return if (accContext != null) AccessController.doPrivileged(
|
|
PrivilegedAction {
|
|
superDoTopCall(callable, cx, scope, thisObj, args)
|
|
}, accContext
|
|
) else superDoTopCall(
|
|
callable,
|
|
cx,
|
|
scope,
|
|
thisObj,
|
|
args
|
|
)
|
|
}
|
|
|
|
private fun superDoTopCall(
|
|
callable: Callable,
|
|
cx: Context,
|
|
scope: Scriptable,
|
|
thisObj: Scriptable,
|
|
args: Array<Any>
|
|
): Any? {
|
|
return super.doTopCall(callable, cx, scope, thisObj, args)
|
|
}
|
|
})
|
|
|
|
if (System.getSecurityManager() != null) {
|
|
try {
|
|
AccessController.checkPermission(AllPermission())
|
|
} catch (var6: AccessControlException) {
|
|
accessContext = AccessController.getContext()
|
|
}
|
|
}
|
|
val cx = Context.enter()
|
|
try {
|
|
topLevel = RhinoTopLevel(cx, this)
|
|
} finally {
|
|
Context.exit()
|
|
}
|
|
indexedProps = HashMap()
|
|
implementor = object : InterfaceImplementor(this) {
|
|
|
|
override fun isImplemented(obj: Any?, clazz: Class<*>): Boolean {
|
|
var obj1 = obj
|
|
return try {
|
|
if (obj1 != null && obj1 !is Scriptable) {
|
|
obj1 = Context.toObject(obj1, topLevel)
|
|
}
|
|
val engineScope = getRuntimeScope(context)
|
|
val localScope = if (obj1 != null) obj1 as Scriptable else engineScope
|
|
val methods = clazz.methods
|
|
val methodsSize = methods.size
|
|
for (index in 0 until methodsSize) {
|
|
val method = methods[index]
|
|
if (method.declaringClass != Any::class.java) {
|
|
if (ScriptableObject.getProperty(
|
|
localScope,
|
|
method.name
|
|
) !is Function
|
|
) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
true
|
|
} finally {
|
|
Context.exit()
|
|
}
|
|
}
|
|
|
|
override fun convertResult(method: Method?, res: Any?): Any? {
|
|
method ?: return null
|
|
val desiredType = method.returnType
|
|
if (desiredType == Void.TYPE) return null
|
|
return Context.jsToJava(res, desiredType)
|
|
}
|
|
}
|
|
}
|
|
|
|
} |