DeflateStream unable to write binary streams?

Andreas Raab andreas.raab at gmx.de
Wed Sep 26 06:33:26 UTC 2007


Matthew Fulmer wrote:
> I was playing with GZipWriteStream and ZLibWriteStream, trying
> to write compressed binary data in the middle of a chunk file,
> like so:
> 
> writeDelta: aDelta
>     stream nextPutAll: '!DSBinStReader new!'.
>     (DataStream on: (GZipWriteStream on: stream)) nextPut: aDelta
> 
> This didn't work at all. First, GZipWriteStream wasn't even
> writing to the stream, but to it's own internal collection.
> DeflateStreams seem to try to seize control of the entire
> underlying stream or collection. 

Well, let's be careful with the claims here. A couple of examples:

1) Simple compression to an existing stream:

(GZipWriteStream on: (FileStream newFileNamed: 'test.gz'))
	nextPutAll: 'Hello World';
	close.

2) Embedding compressed data:

	stream := String new writeStream.
	stream nextPutAll: 'Binary data: '.
	(GZipWriteStream on: stream) nextPutAll: 'Hello World'; finish.
	stream nextPutAll: 'More data follows'.
	stream contents.


3) Embedding compressed binary data in the midst of text:

	stream := RWBinaryOrTextStream on: String new.
	stream nextPutAll: 'Binary data: '.
	stream binary.
	(GZipWriteStream on: stream) nextPut: 123; nextPut: 234; finish.
	stream ascii.
	stream nextPutAll: 'More data follows' asByteArray.
	stream contents.

All of the above examples work fine.

> Second, it wouldn't accept the binary data that DataStream was
> feeding it. It seems to only accept character data, as sending
> the message #binary to a DeflateStream does nothing.

DeflateStreams accept binary data if and only if the target stream is 
binary. They do not allow switching between binary and non-binary in the 
middle of things.

> So, should DeflateStreams be general purpose streams, or is
> there a good reason they are text-only and not embeddable?

Besides it being not true (as the third example above illustrates) it 
wouldn't be a problem if it were. You could trivially solve the problem 
by using:

writeDelta: aDelta
     stream nextPutAll: '!DSBinStReader new!'.
     stream nextPutAll: (DataStream streamedRepresentationOf: aDelta) 
asString zipped.

which is not significantly more complex than your solution and actually 
works - yours doesn't because you either need to #close or #finish the 
compressor to write the last block (remember LZ is block based). Note 
that #flush is *not* enough here since the LZ family of compressors 
marks the last block specifically (#flush will write a block but not 
mark it as the last block and upset the decompressor on reading it).

Cheers,
   - Andreas



More information about the Squeak-dev mailing list