-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathlz4.go
More file actions
141 lines (119 loc) · 5.18 KB
/
Copy pathlz4.go
File metadata and controls
141 lines (119 loc) · 5.18 KB
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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package lz4
// #cgo CFLAGS: -O3
// #include "lz4.h"
import "C"
import (
"errors"
"reflect"
"unsafe"
)
func byteSliceToCharPointer(b []byte) *C.char {
if len(b) == 0 {
return (*C.char)(unsafe.Pointer(nil))
}
return (*C.char)(unsafe.Pointer(&b[0]))
}
func interfaceToCharPointer(i interface{}) *C.char {
if i == nil {
return (*C.char)(unsafe.Pointer(nil))
}
v := reflect.ValueOf(i)
if v.Kind() == reflect.Slice {
return (*C.char)(unsafe.Pointer(v.Index(0).UnsafeAddr()))
} else if v.Kind() == reflect.Ptr {
return (*C.char)(unsafe.Pointer(v.Pointer()))
}
return (*C.char)(unsafe.Pointer(nil))
}
// CompressBound returns the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible).
func CompressBound(size int) int {
return int(C.LZ4_compressBound(C.int(size)))
}
// CompressDefault compresses buffer "source" into already allocated "dest" buffer.
// Compression is guaranteed to succeed if size of "dest" >= CompressBound(size of "src")
// The function returns the number of bytes written into buffer "dest".
// If the function cannot compress "source" into a more limited "dest" budget,
// compression stops immediately, and the function result is zero.
func CompressDefault(source, dest []byte) (int, error) {
ret := int(C.LZ4_compress_default(byteSliceToCharPointer(source),
byteSliceToCharPointer(dest), C.int(len(source)), C.int(len(dest))))
if ret == 0 {
return ret, errors.New("Insufficient destination buffer")
}
return ret, nil
}
// CompressFast works the same as CompressDefault, but allows to select an "acceleration" factor.
// The larger the acceleration value, the faster the algorithm, but also the lesser the compression.
// An acceleration value of "1" is the same as regular CompressDefault()
func CompressFast(source, dest []byte, acceleration int) (int, error) {
ret := int(C.LZ4_compress_fast(byteSliceToCharPointer(source),
byteSliceToCharPointer(dest), C.int(len(source)), C.int(len(dest)),
C.int(acceleration)))
if ret == 0 {
return ret, errors.New("Insufficient destination buffer")
}
return ret, nil
}
// DecompressSafe decompresses buffer "source" into already allocated "dest" buffer.
// The function returns the number of bytes written into buffer "dest".
// If destination buffer is not large enough, decoding will stop and output an error code (<0).
// If the source stream is detected malformed, the function will stop decoding and return a negative result.
func DecompressSafe(source, dest []byte) (int, error) {
ret := int(C.LZ4_decompress_safe(byteSliceToCharPointer(source),
byteSliceToCharPointer(dest), C.int(len(source)), C.int(len(dest))))
if ret < 0 {
return ret, errors.New("Malformed LZ4 source or insufficient destination buffer")
}
return ret, nil
}
// DecompressFast fully respect memory boundaries for properly formed compressed data.
// It is a bit faster than DecompressSafe.
// However, it does not provide any protection against intentionally modified data stream (malicious input).
func DecompressFast(source, dest []byte, originalSize int) (int, error) {
ret := int(C.LZ4_decompress_fast(byteSliceToCharPointer(source),
byteSliceToCharPointer(dest), C.int(originalSize)))
if ret < 0 {
return ret, errors.New("Malformed LZ4 source")
}
return ret, nil
}
// CompressAnyDefault works the same as CompressDefault, but you can pass pointer of struct or slice as a buffer.
// Also, the size of buffer should be specified explicitly.
func CompressAnyDefault(source, dest interface{}, sourceSize, maxDestSize int) (int, error) {
ret := int(C.LZ4_compress_default(interfaceToCharPointer(source),
interfaceToCharPointer(dest), C.int(sourceSize), C.int(maxDestSize)))
if ret == 0 {
return ret, errors.New("Insufficient destination buffer")
}
return ret, nil
}
// CompressAnyFast works the same as CompressFast, but you can pass pointer of struct or slice as a buffer.
// Also, the size of buffer should be specified explicitly.
func CompressAnyFast(source, dest interface{}, sourceSize, maxDestSize, acceleration int) (int, error) {
ret := int(C.LZ4_compress_fast(interfaceToCharPointer(source),
interfaceToCharPointer(dest), C.int(sourceSize), C.int(maxDestSize),
C.int(acceleration)))
if ret == 0 {
return ret, errors.New("Insufficient destination buffer")
}
return ret, nil
}
// DecompressAnySafe works the same as DecompressSafe, but you can pass pointer of struct or slice as a buffer.
// Also, the size of buffer should be specified explicitly.
func DecompressAnySafe(source, dest interface{}, compressedSize, maxDecompressedSize int) (int, error) {
ret := int(C.LZ4_decompress_safe(interfaceToCharPointer(source),
interfaceToCharPointer(dest), C.int(compressedSize), C.int(maxDecompressedSize)))
if ret < 0 {
return ret, errors.New("Malformed LZ4 source or insufficient destination buffer")
}
return ret, nil
}
// DecompressAnyFast works the same as DecompressFast, but you can pass pointer of struct or slice as a buffer.
func DecompressAnyFast(source, dest interface{}, originalSize int) (int, error) {
ret := int(C.LZ4_decompress_fast(interfaceToCharPointer(source),
interfaceToCharPointer(dest), C.int(originalSize)))
if ret < 0 {
return ret, errors.New("Malformed LZ4 source")
}
return ret, nil
}