Coercing pointers

Edi Weitz <[email protected]> 12 Aug 2003 15:01:51 +0200
Newsgroups gmane.lisp.uffi.general
Message-ID <[email protected]>
Hi!

I'm trying to use the GD library <http://www.boutell.com/gd/> with
CMUCL and LW and part of my UFFI code looks like this:

  (def-function ("gdImagePngPtr" gd-image-png-ptr)
      ((im gd-image-ptr)
       (size (* :int)))
    :returning :pointer-void
    :module "gd")

  (defun png-to-stream (stream image)
    (cond ((subtypep (stream-element-type stream) 'character)
            (with-foreign-object (size :int)
              (with-foreign-object (memory :char)
                (setq memory (gd-image-png-ptr image size))
                (dotimes (i (deref-pointer size :int))
                  (write-char (ensure-char-character (deref-array memory '(:array :char) i)) stream)))))
          ((subtypep (stream-element-type stream) '(unsigned-byte 8))
            (with-foreign-object (size :int)
              (with-foreign-object (memory :unsigned-byte)
                (setq memory (gd-image-png-ptr image size))
                (dotimes (i (deref-pointer size :int))
                  (write-byte (deref-array memory '(:array :unsigned-byte) i) stream)))))
          (t (error "Can't use a stream with element-type ~A"
                    (stream-element-type stream)))))

I had hopes that this would work but at least LW seems to have
problems if the return type of GD-IMAGE-PNG-PTR is declared to be
:POINTER-VOID. I get messages like

  Error: Attempted to dereference a pointer to aggregate type :VOID.

Now, I can change the DEF-FUNCTION above and replace :POINTER-VOID
with (* CHAR) or (* (UNSIGNED-BYTE 8)) but in both cases one of the
DEREF-ARRAYs above won't work. To be more specific, if
GD-IMAGE-PNG-PTR is declared to return (* CHAR), then DEREF-ARRAY will
return a character in both COND cases, i.e. the second (type) argument
to DEREF-ARRAY is completely ignored. And vice versa.

Am I doing something wrong or isn't it possible to coerce a
:POINTER-VOID to something else in UFFI? But if that's so what's the
point of having this type?

It is possible to do what I want at least with LW and CMUCL as the
kludgy code below shows:

  (defun png-to-stream (stream image)
    (cond ((subtypep (stream-element-type stream) 'character)
            (with-foreign-object (size :int)
              (with-foreign-object (memory :char)
                (setq memory (gd-image-png-ptr image size))
                (dotimes (i (deref-pointer size :int))
                  (write-char #+lispworks
                              (fli:dereference memory :index i :type :char)
                              #+cmu
                              (code-char (alien:deref (alien:cast memory (* (alien:unsigned 8))) i))
                              stream)))))
          ((subtypep (stream-element-type stream) '(unsigned-byte 8))
            (with-foreign-object (size :int)
              (with-foreign-object (memory :unsigned-byte)
                (setq memory (gd-image-png-ptr image size))
                (dotimes (i (deref-pointer size :int))
                  (write-byte #+lispworks
                              (fli:dereference memory :index i :type '(:unsigned :byte))
                              #+cmu
                              (alien:deref (alien:cast memory (* (alien:unsigned 8))) i)
                              stream)))))
          (t (error "Can't use a stream with element-type ~A"
                    (stream-element-type stream)))))

Thanks,
Edi.