Search code examples
arrayskotlinrhino

Invalid argument when passing ByteArray to javascript through Rhino


I am using Rhino to evaluate some javascript, where I simply pass a ByteArray from kotlin to a function in Javascript. I know it is in bad taste to say this but I am using the same Js file in Swift, and in .Net Core, without an issue with the line that is failing in this case.

As below, I am passing bytes, a ByteArray, to the JS function decodeByteArray(). The line that fails is the one I have marked with the comment //invalid argument

I have checked the ByteArray contents and they are as expected.

Am I doing something wrong or missing something in this?

Javascript

function decodeByteArray(buf) {
    var pbf = new Pbf(buf);
    return JSON.stringify(decode(pbf));
}

function Pbf(buf) {
    this.buf = ArrayBuffer.isView && ArrayBuffer.isView(buf) ? buf : new Uint8Array(buf); 
    this.pos = 0;
    this.type = 0;
    this.length = this.buf.length;
    setUp(this);
}

Kotlin

private fun decodePbfBytes(bytes: ByteArray?): Any? {
    var jsResult: Any? = null;

    var params = arrayOf(bytes)

    val rhino = org.mozilla.javascript.Context.enter()
    rhino.optimizationLevel = -1
    rhino.languageVersion = org.mozilla.javascript.Context.VERSION_ES6
    try{
        val scope = rhino.initStandardObjects()
        val assetManager = MyApp.sharedInstance.assets
        val input = assetManager.open("pbfIndex.js") //the js file containing js code
        val targetReader = InputStreamReader(input)
        rhino.evaluateReader(scope, targetReader, "JavaScript", 1,null)
        val obj = scope.get("decodeByteArray", scope)
        if (obj is org.mozilla.javascript.Function){
            jsResult = obj.call(rhino, scope, scope, params)
            jsResult = org.mozilla.javascript.Context.toString(jsResult)
        }
    }catch (ex: Exception){
        Log.e("Error", ex.localizedMessage)
    }finally {
        org.mozilla.javascript.Context.exit()
    }

    return jsResult
}

Solution

  • Rhino's TypedArray support is a little lacking (see https://mozilla.github.io/rhino/compat/engines.html#ES2015-built-ins-typed-arrays)

    I couldn't get the constructor to take a byte[] directly, but it worked after converting to a javascript array.

    I believe it will work to change new Uint8Array(buf); to new Uint8Array(Array.from(buf));

    While Uint8Array.from is not implemented, Array.from is.