                    Header delegate: (Header) -> Int32,
                        From source: () -> UnsafeBufferPointer<UInt8>) -> (Int, Int)
     {
+        func put() -> Int32
+        {
+            let bytes = 64*1024 - stream.availOut
+            let data = UnsafePointer<UInt8>(scratch)
+            return sink(UnsafeBufferPointer<UInt8>(start: data, count: bytes))
+        }
         let extra   = UnsafeMutableBufferPointer<Bytef>(start: scratch.advancedBy(0*64*1024), count: 64*1024)
         let name    = UnsafeMutableBufferPointer<Bytef>(start: scratch.advancedBy(1*64*1024), count: 64*1024)
         let comment = UnsafeMutableBufferPointer<Bytef>(start: scratch.advancedBy(2*64*1024), count: 64*1024)
-        var hdr = gz_header(
-            text: 0,
-            time: 0,
-            xflags: 0,
-            os: 0,
-            extra: extra.baseAddress, extra_len: 0, extra_max: uInt(extra.count),
-            name: name.baseAddress, name_max: uInt(name.count - 1),
-            comment: comment.baseAddress, comm_max: uInt(comment.count - 1),
-            hcrc: 0, done: 0)
-
-        inflateReset(&stream)
-        inflateGetHeader(&stream, &hdr)
-        stream.next_out = scratch
-        stream.avail_out = 0
-        stream.avail_in = 0
-
+
+        stream.noInput()
         for ( ; ; ()) {
-            if stream.avail_in == 0 {
-                let input = source()
-                let bytes = uInt(input.count)
-                if bytes == 0 { return (Int(Z_OK), Int(stream.total_in)) }
-
-                stream.next_in = UnsafeMutablePointer<Bytef>(input.baseAddress)
-                stream.avail_in = bytes
+            var hdr = gz_header(
+                text: 0,
+                time: 0,
+                xflags: 0,
+                os: 0,
+                extra: extra.baseAddress, extra_len: 0, extra_max: uInt(extra.count),
+                name: name.baseAddress, name_max: uInt(name.count - 1),
+                comment: comment.baseAddress, comm_max: uInt(comment.count - 1),
+                hcrc: 0, done: 0)
+            var noHeader = true;
+
+            stream.InflateReset()
+            stream.getHeader(&hdr)
+            stream.noOutput()
+
+            for ( ; ; ()) {
+                if !stream.hasInput {
+                    let input = source()
+                    let bytes = uInt(input.count)
+                    if bytes == 0 { return (Int(Z_OK), Int(stream.totalIn)) }
+
+                    stream.input = input
+                }
+                let zrc = stream.Inflate(Z_FINISH)
+                switch zrc {
+                case Z_OK:
+                    /* need more input */
+                    continue
+                case Z_BUF_ERROR:
+                    if !stream.hasInput {
+                        continue
+                    }
+                    if noHeader {
+                        name[name.count - 1] = 0
+                        comment[comment.count - 1] = 0
+                        let rc = delegate(Header.make(hdr))
+                        if rc != 0 { return (Int(rc), Int(stream.totalIn)) }
+                        noHeader = false
+                    }
+                    else {
+                        let rc = put()
+                        if rc != 0 { return (Int(rc), Int(stream.totalIn)) }
+                    }
+                    stream.setOutput(scratch, size: 64 * 1024)
+                case Z_STREAM_END:
+                    return (Int(put()), Int(stream.totalIn))
+                default:
+                    println(stream)
+                    return (Int(zrc), Int(stream.totalIn))
+                }
             }
-            let zrc = inflate(&stream, Z_BLOCK)
-            switch zrc {
-            case Z_OK:
-                /* need more input */
-                continue;
-            case Z_BUF_ERROR:
-                if stream.total_out == 0 {
-                    name[name.count - 1] = 0
-                    comment[comment.count - 1] = 0
-                    let rc = delegate(Header.make(hdr))
-                    if rc != 0 { return (Int(rc), Int(stream.total_in)) }
-                }
-                else {
-                    let bytes = 64*1024 - stream.avail_out
-                    let data = UnsafePointer<UInt8>(scratch);
-                    let rc = sink(UnsafeBufferPointer<UInt8>(start: data, count: Int(bytes)))
-                    if rc != 0 { return (Int(rc), Int(stream.total_in)) }
-                }
-                stream.next_out = scratch
-                stream.avail_out = 64*1024
-            default:
-                return (Int(zrc), Int(stream.total_in))
-            }
-        }
-    }
-}
+        }
+    }
+}

private let MAX_WBYTES = Int(1 << MAX_WBITS)

//// TODO: enum for inflate error codes

// callback based inflate
private struct InflateBack

            return .None
        }
    }
    private let scratch = UnsafeMutablePointer<Bytef>.alloc(3 * 64 * 1024)
    private var stream = ZStream()

    init()
    {
        stream.InflateInit(MAX_WBITS + 32)
    }
    deinit
    {
        stream.InflateEnd()
        scratch.dealloc(3 * 64 * 1024)
    }

