AS3 port of JZLib

Last month I was working on a project that used FZip to decompress some zip files in flash.

One tricky thing about FZip is that when running in Flash Player it requires your zip files to have an adler32 checksum for each file in order to work. This is normally fixed with a work around python script provided with FZip.

The python script is easy and all, but why not figure out how to do it in pure AS3 with more standard zip files?

The checksum is needed because AS3’s ByteArray only supports ZLib when running in Flash Player. In AIR it supports deflate which is what zip files use by default. I would be really curious to hear from Adobe why they chose not to support deflate since you need deflate for Zlib to work anyway.

I decided to implement inflate in as3 but I didn’t want to do it with new code so I looked for FOSS projects to port. JZlib was a good choice because Java is similar to AS3 and it didn’t rely on any external system calls.

This port supports everything in JZlib so you can use it for any inflate or deflate operations you might need.

To use with FZip

I used this library in FZip so it no longer requires that zip files be converted before use. It is tested to be working with the OSX cli zip command. It doesn’t work with OSX finder zip compression because of another issue.

In FZipFile.as:

protected function parseContent(data:IDataInput):void {
	if(_compressionMethod === COMPRESSION_DEFLATED && !_encrypted) {
		if(HAS_INFLATE) {
			// Adobe Air supports inflate decompression.
			// If we got here, this is an Air application
			// and we can decompress without using the Adler32 hack
			// so we just write out the raw deflate compressed file
			data.readBytes(_content, 0, _sizeCompressed);
		} else if(_hasAdler32) {
			// Add zlib header
			// CMF (compression method and info)
			_content.writeByte(0x78);
			// FLG (compression level, preset dict, checkbits)
			var flg:uint = (~_deflateSpeedOption << 6) & 0xc0;
			flg += 31 - (((0x78 << 8) | flg) % 31);
			_content.writeByte(flg);
			// Add raw deflate-compressed file
			data.readBytes(_content, 2, _sizeCompressed);
			// Add adler32 checksum
			_content.position = _content.length;
			_content.writeUnsignedInt(_adler32);
		} else {
			data.readBytes(_content, 0, _sizeCompressed);
 
			//throw new Error("Adler32 checksum not found.");
		}
		isCompressed = true;
	} else if(_compressionMethod == COMPRESSION_NONE) {
		data.readBytes(_content, 0, _sizeCompressed);
		isCompressed = false;
	} else {
		throw new Error("Compression method " + _compressionMethod + " is not supported.");
	}
	_content.position = 0;
}
 
protected function uncompress():void {
	if(isCompressed && _content.length > 0) {
		_content.position = 0;
		if(HAS_INFLATE) {
			_content.uncompress.apply(_content, ["deflate"]);
		} else if(_hasAdler32) {
			_content.uncompress();
		} else {
			var uncompr:ByteArray = new ByteArray();
			var d_stream:ZStream=new ZStream();
			d_stream.next_in = _content;
			d_stream.next_in_index = 0;
			d_stream.next_out = uncompr;
			d_stream.next_out_index = 0;
			
			var err:int = d_stream.inflateInitWithNoWrap(true);
			while(d_stream.total_in <= _content.length && i<=_content.length*4) {
				d_stream.avail_in=d_stream.avail_out=10;
			
				err=d_stream.inflate(JZlib.Z_NO_FLUSH);
				if(err == JZlib.Z_STREAM_END) {
					System.println("decompress success:" + this.filename);
					break;
				} else if (err == JZlib.Z_STREAM_ERROR) {
					System.println("stream error:" + this.filename + " " + d_stream.msg);
					break;
				} else if (err == JZlib.Z_DATA_ERROR) {
					System.println("data error:" + this.filename + " " + d_stream.msg);
					break;
				//} else {
				//	System.println("status:" + this.filename + " " + err);
				}				
			}
			err=d_stream.inflateEnd();
 
			_content = uncompr;			
		}
		_content.position = 0;
		isCompressed = false;
	}
}

*** UPDATE 2/9/2010: Thanks to Kathrin Furtlehner for sending me a test case for a bug where it wasn’t extracting the full file when dealing with longer strings. I updated the patched FZip archive to reflect the fix.

Share and Enjoy:
  • Digg
  • del.icio.us
  • Reddit
  • StumbleUpon
  • Technorati
  • Slashdot
  • Tumblr
  • Twitter

25 Responses to “AS3 port of JZLib”

  1. stan Says:

    Hi Tea,

    I would really like to use your Fzip class, but unfortunatelly the source files use a class that I can’t find in the source…: com.wirelust.util.Cast;
    could you please add it to the repository, or somewhere so I can check the usage of your class?

    Thanks,
    Stan

  2. Tea Says:

    Oops. sorry I forgot to check that in. You can get it here:
    http://code.google.com/p/as3zlib/source/browse/trunk/src/com/wirelust/util/Cast.as

    I’ll update the zip archive later on.

  3. Ben Says:

    I made some modifications to this library to fix some flex3 compilation warnings as well as some corruption that occurs when using Z_SYNC_FLUSH. I attempted to send you an email but have no idea if it was the correct address, let me know if you would like me to send you a diff, and thanks!

  4. damned Says:

    Hey Tea,

    I love this library, it works like a charm.. well zipping up data does.. when you use

    var zip:FZip = new Zip();

    // load a file
    // add listeners

    var file:FZipFile = zip.getFileAt(FILE_INDEX);

    Does matter if its an image or in my case I tried \utf-8\ text.. It chops off alittle of the end.. Why is that?? Thanks

  5. iongion Says:

    Are you sure this really works ?
    I am trying to build a swc in flex containing this code, but i get language errors

    - the \in\ variables, in as3, \in\ – is keyword
    - the throws at the end of each method, in java this is possible, in as3 i doubt

    Please, make it work

  6. mxmlc Says:

    how to use the fzip-prepare.py? pls reaply me via this email

  7. Thierry Says:

    Hello,
    I use your classe, it works well, but for texts files (in my case xml files) the getContentAsString cut the end of the string….
    If do you plan to fix it, it would be very kind of you !!
    Thanks
    Thierry

  8. Tea Says:

    Please email me an example project where this is happening and I will look into fixing it. Unfortunately I don’t have time to investigate without knowing the exact nature of the problem.

  9. Tea Says:

    @Thierry: this issue has been tracked down and is fixed in the latest copy of the zip.

  10. shaning Says:

    Using the code above, the error: Adler32 checksum not found. was gone. However, I got another error at

    protected function uncompress():void {
    if(isCompressed && _content.length > 0) {
    _content.position = 0;
    if(HAS_INFLATE) {
    _content.uncompress.apply(_content, [deflate]);
    } else {
    _content.uncompress(); // Error at Line 562
    }
    _content.position = 0;
    isCompressed = false;
    }
    }

    Anyone can help? Thanks.
    __________________________

    Error: Error #2058: There was an error decompressing the data.
    at flash.utils::ByteArray/_uncompress()
    at flash.utils::ByteArray/uncompress()
    at deng.fzip::FZipFile/uncompress()[C:Documents and Settingsshaning.yuMy DocumentsFlex Builder 3myTestsrcdeng zipFZipFile.as:562]
    at deng.fzip::FZipFile/get content()[C:Documents and Settingsshaning.yuMy DocumentsFlex Builder 3myTestsrcdeng zipFZipFile.as:144]
    at FileZip/onEnterFrame()[C:Documents and Settingsshaning.yuMy DocumentsFlex Builder 3myTestsrcFileZip.mxml:61]

  11. shaning Says:

    where and how can I get ZStream?

  12. Tea Says:

    ZStream is in the as3zlib zip. you need to download that and merge it with the modified fzip code,

  13. shaning Says:

    Downloaded. Could you kind provide How to do for the downloaded as3zlib zip? Thanks.

  14. Tea Says:

    The two zips can be combined into a single src folder. sorry I don’t have time to provide much support beyond this.

  15. shaning Says:

    Got how to do already.

  16. shaning Says:

    New problem if anyone can help:
    Can’t find com.wirelust.util.Cast
    In the downloaded zip, there is no com/wirelust/util
    If it is a simple as file or a a bundle of files, could you email me at mrgis08@yahoo.com? Thanks.

  17. shaning Says:

    Got it already. Never mind. Thanks.

  18. Tea Says:

    I updated the link to the zip with the latest copy from subversion. Cast should be in there. as3zlib_snapshot_20100303.zip

  19. shaning Says:

    Got an error at
    while(d_stream.total_in <= _content.length && i<=_content.length*4)

    where i is undefined. I guess var i:int should defined somewhere in the source code. Could someone help for this issue? Thanks.

  20. shaning Says:

    I tried to unzip a folder; states.zip, which contains 5 dozens of txt file.

    public function FZipTest() {
    zip = new FZip();
    zip.addEventListener(Event.OPEN, onOpen);
    zip.addEventListener(Event.COMPLETE, onComplete);
    zip.load(new URLRequest(\states.zip\)); // in the same directory of this file’s swf
    }

    However, I got such an error:

    Error #2044: Unhandled IOErrorEvent:. text=Error #2124: Loaded file is an unknown type.
    Can anyone hint me where the file type should be defined? Thanks.

  21. shaning Says:

    Question: can flash.display.Loader be used to load a textfile in a zip? I got
    Error #2124: Loaded file is an unknown type.

  22. shaning Says:

    Is it true for the following statements:
    1) flash.net.URLLoader does not support to load a file in zip.
    2) flash.display.Loader does not support to load a textfile.
    Thanks if you can share your experience.

  23. Tea Says:

    I have no idea what you are trying to do since you didn’t post any code that you are having issues with. URLLoader is well documented by adobe and I suggest you look up its capabilities on google.
    Here is an example of uncompressing and loading a text file:

    public class fzip extends Sprite
    {
    private var zip:FZip;

    public function fzip()
    {
    zip = new FZip();
    zip.addEventListener(Event.COMPLETE, onComplete);
    zip.load(new URLRequest(“20100129.zip”));
    }

    private function onComplete(e:Event):void
    {
    trace(“zip complete”);

    var file:FZipFile = zip.getFileAt(0);

    trace(file.getContentAsString(true));
    }
    }

  24. shaning Says:

    I used the code, it is helpful. I have one more Q: The file is textfile, how can I load its content into a string? Thanks.

  25. shaning Says:

    Problems solved. I created Related code is below:

    private var JData:ByteArray;

    var dobj:Object;
    dobj = JSON.decode(JData.readUTFBytes(JData.bytesAvailable));

Leave a Reply