-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathreader.go
120 lines (101 loc) · 2.88 KB
/
reader.go
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package archive
/*
#cgo pkg-config: libarchive
#include <archive.h>
#include <archive_entry.h>
#include <stdlib.h>
#include "reader.h"
*/
import "C"
import (
"io"
"unsafe"
)
// Reader represents libarchive archive
type Reader struct {
archive *C.struct_archive
reader io.Reader // the io.Reader from which we Read
buffer []byte // buffer for the raw reading
index int64 // current reading index
}
// NewReader returns new Archive by calling archive_read_open
func NewReader(reader io.Reader) (r *Reader, err error) {
r = new(Reader)
r.buffer = make([]byte, 1024)
r.archive = C.archive_read_new()
C.archive_read_support_filter_all(r.archive)
C.archive_read_support_format_all(r.archive)
r.reader = reader
e := C.go_libarchive_open(r.archive, unsafe.Pointer(r))
err = codeToError(r.archive, int(e))
return
}
//export myopen
func myopen(archive *C.struct_archive, client_data unsafe.Pointer) C.int {
// actually write something
return ARCHIVE_OK
}
//export myclose
func myclose(archive *C.struct_archive, client_data unsafe.Pointer) C.int {
// actually write something
return ARCHIVE_OK
}
//export myread
func myread(archive *C.struct_archive, client_data unsafe.Pointer, block unsafe.Pointer) C.size_t {
reader := (*Reader)(client_data)
read, err := reader.reader.Read(reader.buffer)
if err != nil && err != ErrArchiveEOF {
// set error
read = -1
}
*(*uintptr)(block) = uintptr(unsafe.Pointer(&reader.buffer[0]))
return C.size_t(read)
}
// Next calls archive_read_next_header and returns an
// interpretation of the ArchiveEntry which is a wrapper around
// libarchive's archive_entry, or Err.
//
// ErrArchiveEOF is returned when there
// is no more to be read from the archive
func (r *Reader) Next() (ArchiveEntry, error) {
e := new(entryImpl)
errno := int(C.archive_read_next_header(r.archive, &e.entry))
err := codeToError(r.archive, errno)
if err != nil {
e = nil
}
return e, err
}
// Read calls archive_read_data which reads the current archive_entry.
// It acts as io.Reader.Read in any other aspect
func (r *Reader) Read(b []byte) (n int, err error) {
n = int(C.archive_read_data(r.archive, unsafe.Pointer(&b[0]), C.size_t(cap(b))))
if n == 0 {
err = ErrArchiveEOF
} else if 0 > n { // err
err = codeToError(r.archive, ARCHIVE_FAILED)
n = 0
}
r.index += int64(n)
return
}
// Size returns compressed size of the current archive entry
func (r *Reader) Size() int {
return int(C.archive_filter_bytes(r.archive, C.int(0)))
}
// Free frees the resources the underlying libarchive archive is using
// calling archive_read_free
func (r *Reader) Free() error {
if C.archive_read_free(r.archive) == ARCHIVE_FATAL {
return ErrArchiveFatal
}
return nil
}
// Close closes the underlying libarchive archive
// calling archive read_cloe
func (r *Reader) Close() error {
if C.archive_read_close(r.archive) == ARCHIVE_FATAL {
return ErrArchiveFatal
}
return nil
}