Hi Yu,

On Mon, Nov 9, 2009 at 7:12 PM, Feng Yu <[email protected]> wrote:
> On Sun, Oct 4, 2009 at 7:25 AM, Philipp Zabel <[email protected]> wrote:
>
>> Hi,
>>
>> Does anybody have example code that uses the ZLib bindings? I tried to
>> implement the example described at http://zlib.net/zlib_how.html for
>> inflation, but compilation failed with errors from gcc about STATUS_OK
>> etc. symbols not being found. The following patch helped with that for
>> some reason.
>>
>> Also, I don't understand how Vala can handle memory for the next_in and
>> next_out pointers when the inflate call is changing those pointers under
>> its nose. Wouldn't it be more realistic not to wrap them as an array?
>>
>>
> I believe old vapi binding for next_in and next_out still works. Vala don't
> manage the memory of struct types declared in vapi files.
>
> If you are sure the buffer is not owned by the struct and you want to
> explicitly mention this in the vapi file, use 'unowned'. Change the
> signature to 'unowned uchar[]' in this case.

Yes, you are right. With the following patch (against 0.7.8) ...

diff --git a/vapi/zlib.vapi b/vapi/zlib.vapi
index bb85db7..db9579d 100644
--- a/vapi/zlib.vapi
+++ b/vapi/zlib.vapi
@@ -90,10 +90,11 @@ namespace ZLib {
        }
        [CCode (cname = "z_stream", destroy_function = "deflateEnd")]
        public struct Stream {
-               public uchar* next_in;
-               public uint avail_in;
+               [CCode (array_length_cname = "avail_in", array_length_type = 
"guint")]
+               public weak uchar[] next_in;
                public ulong total_in;
-               public uchar* next_out;
+               [CCode (array_length_cname = "avail_out", array_length_type = 
"guint")]
+               public weak uchar[] next_out;
                public uint avail_out;
                public ulong total_out;
                public string? msg;

.. I can also make my example work if I assign to the weak uchar array's length:

        InputStream source = File.new_for_path ("test.gz").read (null);
        uchar[] buf_in = new uchar[16384];
        uchar[] buf_out = new uchar[16384];

        var strm = InflateStream.full (15 | 32);   // no way to check if this 
failed...

        strm.next_in = buf_in;
        strm.next_out = buf_out;
        strm.next_in.length = (int) source.read (strm.next_in,
strm.next_in.length, null);
        // ^ ^ ^ ^ ^ ^ ^ here
        if (strm.next_in.length == 0)
                return;
        int ret = strm.inflate (Flush.NO_FLUSH);

I still maintain that strm.next_in / strm.next_out cannot be owned
arrays because the call to strm.inflate changes the pointers
themselves. The same program compiles unchanged when I remove the weak
keywords again, but it fails when trying to destroy the buffers:
*** glibc detected *** ./zlibtest: munmap_chunk(): invalid pointer:
0x000000000210b500 ***

> Please avoid pointers if possible in vapi bindings. Pointers forces
> programers write '->'s and makes the code C++-ish.

The '->' argument doesn't apply here - uchar* vs uchar[], no structs involved.
But I agree that a single weak uchar[] is more Valaish than a uchar* and an int.
The initial assignment is more compact this way:
        strm.next_out = buf_out;
vs
        strm.next_out = buf_out;
        strm.avail_out = buf_in.length;
And I have to replace strm.avail_out with stream.next_out.length.
Other than that,
it's the same. So should we change that back (to weak uchar[]s)?

> Remember your vapi file is going to be used by others and will affect their
> programming styles. The influence might be permanent.

Thanks for having a look at this.

regards
Philipp
using GLib;
using ZLib;

class ZLibTest : Object {
	// 16KB buffer size
	const int CHUNK = 16*1024;

	uchar[] buf_in;
	uchar[] buf_out;

	construct {
		buf_in = new uchar[CHUNK];
		buf_out = new uchar[CHUNK];
	}

	public int inflate (InputStream source, OutputStream dest) throws Error {
		uint have;
		int ret = Status.OK;
		var strm = InflateStream.full (15 | 32);   // no way to check if this failed...

		// decompress until deflate stream ends or end of file
		do {
			strm.next_in = buf_in;
			strm.next_in.length = (int) source.read (strm.next_in, strm.next_in.length, null);
			if (strm.next_in.length == 0)
				break;

			// run inflate() on input until output buffer not full
			do {
				strm.next_out = buf_out;

				ret = strm.inflate (Flush.NO_FLUSH);
				assert (ret != Status.STREAM_ERROR);  // state not clobbered
				if (ret == Status.NEED_DICT)
					ret = Status.DATA_ERROR;      // and fall through
				switch (ret) {
				case Status.DATA_ERROR:
				case Status.MEM_ERROR:
					return ret;
				}

				have = CHUNK - strm.next_out.length;
				if (dest.write (buf_out, have, null) != have)
					return Status.ERRNO;
			} while (strm.avail_out == 0);

			// done when inflate () says it's done
		} while (ret != Status.STREAM_END);

		return ret == Status.STREAM_END ? Status.OK : Status.DATA_ERROR;
	}

	public static int main (string[] argv) {
		var zlib_test = new ZLibTest ();
		var infile = File.new_for_path ("test.gz");
		var outfile = File.new_for_path ("test.jpg");
		InputStream instream;
		OutputStream outstream;

		try {
			instream = infile.read (null);
			outstream = outfile.create (FileCreateFlags.NONE, null);
			return zlib_test.inflate (instream, outstream);
		} catch (Error e) {
			stderr.printf ("Error: %s\n", e.message);
			return -1;
		}
	}
}
_______________________________________________
Vala-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/vala-list

Reply via email to