File: reader.go

package info (click to toggle)
golang-github-remyoudompheng-go-liblzma 0.0~git20190506.81bf2d4-3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, experimental, forky, sid, trixie
  • size: 128 kB
  • sloc: makefile: 4
file content (100 lines) | stat: -rw-r--r-- 2,163 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
// Copyright 2011-2019 Rémy Oudompheng. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package xz

/*
#cgo LDFLAGS: -llzma
#include <lzma.h>
#include <stdlib.h>

int go_lzma_code(
    lzma_stream* handle,
    void* next_in,
    void* next_out,
    lzma_action action
) {
    handle->next_in = next_in;
    handle->next_out = next_out;
    return lzma_code(handle, action);
}
*/
import "C"

import (
	"io"
	"math"
	"unsafe"
)

type Decompressor struct {
	handle *C.lzma_stream
	rd     io.Reader
	buffer []byte // buffer allocated when the Decompressor was created to hold data read from rd
	offset int    // offset of the next byte in the buffer to read
	length int    // number of actual bytes in the buffer from the reader
}

var _ io.ReadCloser = &Decompressor{}

func NewReader(r io.Reader) (*Decompressor, error) {
	dec := new(Decompressor)
	dec.rd = r
	dec.buffer = make([]byte, DefaultBufsize)
	dec.offset = DefaultBufsize
	dec.handle = allocLzmaStream(dec.handle)
	// Initialize decoder
	ret := C.lzma_auto_decoder(dec.handle, C.uint64_t(math.MaxUint64),
		C.uint32_t(concatenated))
	if Errno(ret) != Ok {
		return nil, Errno(ret)
	}

	return dec, nil
}

func (r *Decompressor) Read(out []byte) (out_count int, er error) {
	if r.offset >= r.length {
		n, err := r.rd.Read(r.buffer)

		if err != nil && err != io.EOF {
			return 0, err
		}
		r.offset, r.length = 0, n
		r.handle.avail_in = C.size_t(n)
	}
	r.handle.avail_out = C.size_t(len(out))
	action := Run
	if r.handle.avail_in == 0 {
		action = Finish
	}
	ret := C.go_lzma_code(
		r.handle,
		unsafe.Pointer(&r.buffer[r.offset]),
		unsafe.Pointer(&out[0]),
		C.lzma_action(action),
	)
	r.offset = r.length - int(r.handle.avail_in)
	switch Errno(ret) {
	case Ok:
		er = nil
	case StreamEnd:
		er = io.EOF
	default:
		er = Errno(ret)
	}

	return len(out) - int(r.handle.avail_out), er
}

// Frees any resources allocated by liblzma. It does not close the
// underlying reader.
func (r *Decompressor) Close() error {
	if r != nil {
		C.lzma_end(r.handle)
		C.free(unsafe.Pointer(r.handle))
		r.handle = nil
	}
	return nil
}