From: Bulent Murtezaoglu
Subject: make-****-input-stream
Date: 
Message-ID: <87wuvsazu7.fsf@nkapi.internal>
I am whipping up little code to extract image dimension information from
jpeg images.  The images will sometimes be in arrays of (byte 8) sometimes
on disk files.  This entails scanning for specific markers until you get 
to the size info (there is no set place in the header you have to scan).  
Anyhow, I thought it would be good  if I could just write the routine for 
streams and use the analogue of make-string-input-stream for (byte 8)  
except that such a thing doesn't seem to exist.  The Hyperspec seems to give 
no clue about turning arrays into a streams.  Where do I find clues about 
how one might do it w/o going into extensions?  Or is this where I finally 
get the motivation to read about Gray streams and simple streams?

thanks,

BM

From: Kent M Pitman
Subject: Re: make-****-input-stream
Date: 
Message-ID: <sfwbsd3j0r8.fsf@shell01.TheWorld.com>
Bulent Murtezaoglu <··@acm.org> writes:

> I am whipping up little code to extract image dimension information from
> jpeg images.  The images will sometimes be in arrays of (byte 8) sometimes
> on disk files.  This entails scanning for specific markers until you get 
> to the size info (there is no set place in the header you have to scan).  
> Anyhow, I thought it would be good  if I could just write the routine for 
> streams and use the analogue of make-string-input-stream for (byte 8)  
> except that such a thing doesn't seem to exist.  The Hyperspec seems to give 
> no clue about turning arrays into a streams.

Because it has nothing to offer, I think. :(

> Where do I find clues about how one might do it w/o going into
> extensions?

This space left intentionally (almost) blank.

> Or is this where I finally get the motivation to read
> about Gray streams and simple streams?

Yes, Gray streams or the Franz simple streams are your
friend here.  It's quite sad CL doesn't have this.  I agree it'd be
quite useful...

If you want portability, you want to use READ-SEQUENCE to grab blocks 
of data out of files and then put the core of your scanner into a function
that takes an array and the option to ask for another array when it wants
more, and then use array operations.

e.g.,

 (defun parse-jpeg (data-fn)
   (let (...state...)
     (loop for data = (funcall data-fn)
           for state = (make-jpeg-state)
           while data
           do (dotimes (i (length data))
                (let ((byte (aref data i)))
                  ...)))))

Then have your file parser do something that passes 
   #'(lambda () ... (read-sequence ...) ...)
do the parser while having your in-core array processor just do
   #'(lambda () the-whole-array)

This maybe isn't the structural organization of first choice, but
probably works portably ...
From: Bulent Murtezaoglu
Subject: Re: make-****-input-stream
Date: 
Message-ID: <87u1qvb9yf.fsf@nkapi.internal>
>>>>> "KMP" == Kent M Pitman <······@world.std.com> writes:

Back as promised and immediately back to being informative.  Thanks!

[workable skeleton deleted]
    KMP> This maybe isn't the structural organization of first choice,
    KMP> but probably works portably ...

Yes it would, I think.  I am leaning towards just renaming the sequential 
access functions used inside the header parser and wrapping a CLOS class 
that adds a next-unread pointer around the array.  Then the sequential 
access generic functions can dispatch appropriately based on what the 
"stream" argument actually is.  I think that's a least effort kludge 
though, and I agree with Erik (and yourself) that this omission from CL 
is unfortunate.  Of course if I weren't just playing and obsessing about 
out-of-the box portability, Erik's suggested solution would be the cleanest.
 
Thank you both.

cheers,

BM
From: Erik Naggum
Subject: Re: make-****-input-stream
Date: 
Message-ID: <3226641546765711@naggum.net>
* Bulent Murtezaoglu
| Anyhow, I thought it would be good if I could just write the routine for
| streams and use the analogue of make-string-input-stream for (byte 8)
| except that such a thing doesn't seem to exist.  The Hyperspec seems to
| give no clue about turning arrays into a streams.

  The string-stream is basically a stream that has a string for buffer.
  Buffer management is not part of Common Lisp, which I personally think is
  a tragedy, so there is no way you can make a (standard) stream with a
  buffer that utilizes an existing object.  That would have been so very
  useful in so many cases.  *sigh*

| Where do I find clues about how one might do it w/o going into
| extensions?

  Look around in the internals of your implementation to find out how you
  can create a specialized-vector-stream based on how string-streams are
  made.  It should actually not be too hard to find out.  From a cursory
  look at the source code that comes with a supported Allegro CL license
  (i.e., not the Trial editions), it should be doable at user level.  I am
  quite certain that CMUCL and CLISP come with a sufficiently good streams
  class hierarchy that you can whip together your own vector-stream in no
  time.

| Or is this where I finally get the motivation to read about Gray streams
| and simple streams?

  Yes, you would do this with Gray streams if you were to roll your own,
  but I would strongly suggest poking around in your systems internals
  first.  Remember: portable code depends on unportable support code, so if
  you look for a portable way to do something like this, you will not find
  it, but if you write unportable code to support something that could be
  implemented with the same functionality everywhere, you are in business.

///
-- 
  In a fight against something, the fight has value, victory has none.
  In a fight for something, the fight is a loss, victory merely relief.