Today, I spent a bit of time trying to figure out a way to efficiently
compute message digest for Quicklisp. After confirming that
java.security.MessageDigest implements the required digests, I noticed
we didn't have a way to easily get at the underlying Java byte[] array
in (SIMPLE-VECTOR (UNSIGNED-BYTE 8)). So, I patched the underlying Java
code as attached, and wrote the following routine:
(defun sha-256 (path)
(let ((buffer (make-array 8192 :element-type '(unsigned-byte 8))
(digest (jstatic "getInstance" "java.security.MessageDigest"
"SHA-256")))
(with-open-file (in path :element-type '(unsigned-byte 8))
(loop :for bytes = (read-sequence buffer in)
:while (plusp bytes)
:do (jcall-raw "update" digest (make-immediate-object
buffer) 0 bytes))
(jcall "digest" digest)))))
But then I noticed that MAKE-IMMEDIATE-OBJECT calls JOBJECT-LISP-VALUE
which makes no conceptual sense. The doc for MAKE-IMMEDIATE-OBJECT
reads "[a]ttempts to coerce a given Lisp object into a java-object"
while the doc JOBJECT-LISP-VALUE reads "Attempts to coerce JAVA-OBJECT
into a Lisp object". This seems wrong here, but I don't understand how
exactly. I think we need to distinguish three types of values here:
JAVA-OBJECT, LispObject, and the "raw" value of the Java. How should we
really structure our Java FFI here?
With my patch, for an underlying lisp value of type (SIMPLE-VECTOR
(UNSIGNED-BYTE 8)), both MAKE-IMMEDIATE-OBJECT and JOBJECT-LISP-OBJECT
return the byte[] array. I would think that MAKE-IMMEDIATE-OBJECT
should just do this, which JOBJECT-LISP-OBJECT should .... return an
error if its argument isn't of type JAVA-OBJECT? I don't know. I am
confused.
Can someone help me understand the right way forward here?
--
"A screaming comes across the sky. It has happened before, but there
is nothing to compare to it now."