Example #1
0
func (z *reader) Read(p []byte) (int, error) {
	if z.err != nil {
		return 0, z.err
	}

	if len(p) == 0 {
		return 0, nil
	}

	// read and deflate until the output buffer is full
	z.strm.next_out = (*C.Bytef)(unsafe.Pointer(&p[0]))
	z.strm.avail_out = (C.uInt)(len(p))

	for {
		// if we have no data to inflate, read more
		if !z.skipIn && z.strm.avail_in == 0 {
			var n int
			n, z.err = z.r.Read(z.in)
			if (z.err != nil && z.err != io.EOF) || (n == 0 && z.err == io.EOF) {
				C.inflateEnd(&z.strm)
				return 0, z.err
			}

			z.strm.next_in = (*C.Bytef)(unsafe.Pointer(&z.in[0]))
			z.strm.avail_in = (C.uInt)(n)
		} else {
			z.skipIn = false
		}

		// inflate some
		ret := C.inflate(&z.strm, C.Z_NO_FLUSH)
		switch ret {
		case Z_NEED_DICT:
			ret = Z_DATA_ERROR
			fallthrough
		case Z_DATA_ERROR, Z_MEM_ERROR:
			z.err = fmt.Errorf("cgzip: failed to inflate (%v): %v", ret, C.GoString(z.strm.msg))
			C.inflateEnd(&z.strm)
			return 0, z.err
		}

		// if we read something, we're good
		have := len(p) - int(z.strm.avail_out)
		if have > 0 {
			z.skipIn = ret == Z_OK && z.strm.avail_out == 0
			return have, z.err
		}
	}
	panic("Unreachable")
}
Example #2
0
// Close closes the Reader. It does not close the underlying io.Reader.
func (z *reader) Close() error {
	if z.err != nil {
		if z.err != io.EOF {
			return z.err
		}
		return nil
	}
	C.inflateEnd(&z.strm)
	z.err = io.EOF
	return nil
}
Example #3
0
func (z *reader) Read(p []byte) (int, error) {
	if z.err != nil {
		return 0, z.err
	}

	if len(p) == 0 {
		return 0, nil
	}

	// read and deflate until the output buffer is full
	z.strm.next_out = (*C.Bytef)(unsafe.Pointer(&p[0]))
	z.strm.avail_out = (C.uInt)(len(p))

	for {
		// if we have no data to inflate, read more
		if !z.skipIn && z.strm.avail_in == 0 {
			var n int
			n, z.err = z.r.Read(z.in)
			// If we got data and EOF, pretend we didn't get the
			// EOF.  That way we will return the right values
			// upstream.  Note this will trigger another read
			// later on, that should return (0, EOF).
			if n > 0 && z.err == io.EOF {
				z.err = nil
			}

			// FIXME(alainjobart) this code is not compliant with
			// the Reader interface. We should process all the
			// data we got from the reader, and then return the
			// error, whatever it is.
			if (z.err != nil && z.err != io.EOF) || (n == 0 && z.err == io.EOF) {
				C.inflateEnd(&z.strm)
				return 0, z.err
			}

			z.strm.next_in = (*C.Bytef)(unsafe.Pointer(&z.in[0]))
			z.strm.avail_in = (C.uInt)(n)
		} else {
			z.skipIn = false
		}

		// inflate some
		ret := C.inflate(&z.strm, C.Z_NO_FLUSH)
		switch ret {
		case Z_NEED_DICT:
			ret = Z_DATA_ERROR
			fallthrough
		case Z_DATA_ERROR, Z_MEM_ERROR:
			z.err = fmt.Errorf("cgzip: failed to inflate (%v): %v", ret, C.GoString(z.strm.msg))
			C.inflateEnd(&z.strm)
			return 0, z.err
		}

		// if we read something, we're good
		have := len(p) - int(z.strm.avail_out)
		if have > 0 {
			z.skipIn = ret == Z_OK && z.strm.avail_out == 0
			return have, z.err
		}
	}
}