heatshrink 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/ext/heatshrink/extconf.rb +3 -0
- data/ext/heatshrink/heatshrink_common.h +20 -0
- data/ext/heatshrink/heatshrink_config.h +26 -0
- data/ext/heatshrink/heatshrink_decoder.c +367 -0
- data/ext/heatshrink/heatshrink_decoder.h +100 -0
- data/ext/heatshrink/heatshrink_encoder.c +604 -0
- data/ext/heatshrink/heatshrink_encoder.h +109 -0
- data/ext/heatshrink/heatshrink_ruby.c +98 -0
- data/lib/heatshrink.rb +14 -0
- metadata +68 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
#ifndef HEATSHRINK_ENCODER_H
|
2
|
+
#define HEATSHRINK_ENCODER_H
|
3
|
+
|
4
|
+
#include <stdint.h>
|
5
|
+
#include <stddef.h>
|
6
|
+
#include "heatshrink_common.h"
|
7
|
+
#include "heatshrink_config.h"
|
8
|
+
|
9
|
+
typedef enum {
|
10
|
+
HSER_SINK_OK, /* data sunk into input buffer */
|
11
|
+
HSER_SINK_ERROR_NULL=-1, /* NULL argument */
|
12
|
+
HSER_SINK_ERROR_MISUSE=-2, /* API misuse */
|
13
|
+
} HSE_sink_res;
|
14
|
+
|
15
|
+
typedef enum {
|
16
|
+
HSER_POLL_EMPTY, /* input exhausted */
|
17
|
+
HSER_POLL_MORE, /* poll again for more output */
|
18
|
+
HSER_POLL_ERROR_NULL=-1, /* NULL argument */
|
19
|
+
HSER_POLL_ERROR_MISUSE=-2, /* API misuse */
|
20
|
+
} HSE_poll_res;
|
21
|
+
|
22
|
+
typedef enum {
|
23
|
+
HSER_FINISH_DONE, /* encoding is complete */
|
24
|
+
HSER_FINISH_MORE, /* more output remaining; use poll */
|
25
|
+
HSER_FINISH_ERROR_NULL=-1, /* NULL argument */
|
26
|
+
} HSE_finish_res;
|
27
|
+
|
28
|
+
#if HEATSHRINK_DYNAMIC_ALLOC
|
29
|
+
#define HEATSHRINK_ENCODER_WINDOW_BITS(HSE) \
|
30
|
+
((HSE)->window_sz2)
|
31
|
+
#define HEATSHRINK_ENCODER_LOOKAHEAD_BITS(HSE) \
|
32
|
+
((HSE)->lookahead_sz2)
|
33
|
+
#define HEATSHRINK_ENCODER_INDEX(HSE) \
|
34
|
+
((HSE)->search_index)
|
35
|
+
struct hs_index {
|
36
|
+
uint16_t size;
|
37
|
+
int16_t index[];
|
38
|
+
};
|
39
|
+
#else
|
40
|
+
#define HEATSHRINK_ENCODER_WINDOW_BITS(_) \
|
41
|
+
(HEATSHRINK_STATIC_WINDOW_BITS)
|
42
|
+
#define HEATSHRINK_ENCODER_LOOKAHEAD_BITS(_) \
|
43
|
+
(HEATSHRINK_STATIC_LOOKAHEAD_BITS)
|
44
|
+
#define HEATSHRINK_ENCODER_INDEX(HSE) \
|
45
|
+
(&(HSE)->search_index)
|
46
|
+
struct hs_index {
|
47
|
+
uint16_t size;
|
48
|
+
int16_t index[2 << HEATSHRINK_STATIC_WINDOW_BITS];
|
49
|
+
};
|
50
|
+
#endif
|
51
|
+
|
52
|
+
typedef struct {
|
53
|
+
uint16_t input_size; /* bytes in input buffer */
|
54
|
+
uint16_t match_scan_index;
|
55
|
+
uint16_t match_length;
|
56
|
+
uint16_t match_pos;
|
57
|
+
uint16_t outgoing_bits; /* enqueued outgoing bits */
|
58
|
+
uint8_t outgoing_bits_count;
|
59
|
+
uint8_t flags;
|
60
|
+
uint8_t state; /* current state machine node */
|
61
|
+
uint8_t current_byte; /* current byte of output */
|
62
|
+
uint8_t bit_index; /* current bit index */
|
63
|
+
#if HEATSHRINK_DYNAMIC_ALLOC
|
64
|
+
uint8_t window_sz2; /* 2^n size of window */
|
65
|
+
uint8_t lookahead_sz2; /* 2^n size of lookahead */
|
66
|
+
#if HEATSHRINK_USE_INDEX
|
67
|
+
struct hs_index *search_index;
|
68
|
+
#endif
|
69
|
+
/* input buffer and / sliding window for expansion */
|
70
|
+
uint8_t buffer[];
|
71
|
+
#else
|
72
|
+
#if HEATSHRINK_USE_INDEX
|
73
|
+
struct hs_index search_index;
|
74
|
+
#endif
|
75
|
+
/* input buffer and / sliding window for expansion */
|
76
|
+
uint8_t buffer[2 << HEATSHRINK_ENCODER_WINDOW_BITS(_)];
|
77
|
+
#endif
|
78
|
+
} heatshrink_encoder;
|
79
|
+
|
80
|
+
#if HEATSHRINK_DYNAMIC_ALLOC
|
81
|
+
/* Allocate a new encoder struct and its buffers.
|
82
|
+
* Returns NULL on error. */
|
83
|
+
heatshrink_encoder *heatshrink_encoder_alloc(uint8_t window_sz2,
|
84
|
+
uint8_t lookahead_sz2);
|
85
|
+
|
86
|
+
/* Free an encoder. */
|
87
|
+
void heatshrink_encoder_free(heatshrink_encoder *hse);
|
88
|
+
#endif
|
89
|
+
|
90
|
+
/* Reset an encoder. */
|
91
|
+
void heatshrink_encoder_reset(heatshrink_encoder *hse);
|
92
|
+
|
93
|
+
/* Sink up to SIZE bytes from IN_BUF into the encoder.
|
94
|
+
* INPUT_SIZE is set to the number of bytes actually sunk (in case a
|
95
|
+
* buffer was filled.). */
|
96
|
+
HSE_sink_res heatshrink_encoder_sink(heatshrink_encoder *hse,
|
97
|
+
uint8_t *in_buf, size_t size, size_t *input_size);
|
98
|
+
|
99
|
+
/* Poll for output from the encoder, copying at most OUT_BUF_SIZE bytes into
|
100
|
+
* OUT_BUF (setting *OUTPUT_SIZE to the actual amount copied). */
|
101
|
+
HSE_poll_res heatshrink_encoder_poll(heatshrink_encoder *hse,
|
102
|
+
uint8_t *out_buf, size_t out_buf_size, size_t *output_size);
|
103
|
+
|
104
|
+
/* Notify the encoder that the input stream is finished.
|
105
|
+
* If the return value is HSER_FINISH_MORE, there is still more output, so
|
106
|
+
* call heatshrink_encoder_poll and repeat. */
|
107
|
+
HSE_finish_res heatshrink_encoder_finish(heatshrink_encoder *hse);
|
108
|
+
|
109
|
+
#endif
|
@@ -0,0 +1,98 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
// TODO: debug
|
3
|
+
#include <stdio.h>
|
4
|
+
|
5
|
+
#include "heatshrink_encoder.h"
|
6
|
+
#include "heatshrink_decoder.h"
|
7
|
+
|
8
|
+
#define INPUT_BUFFER_SIZE 256
|
9
|
+
|
10
|
+
struct Buffer {
|
11
|
+
uint8_t *p;
|
12
|
+
size_t n;
|
13
|
+
};
|
14
|
+
|
15
|
+
// sink data from src buffer into xcoder
|
16
|
+
#define HSRUBY_SINK(K, kind, src, hsd) \
|
17
|
+
do { \
|
18
|
+
size_t nread; \
|
19
|
+
HS##K##_sink_res sres = \
|
20
|
+
heatshrink_##kind##_sink(hsx, src.p, src.n, &nread); \
|
21
|
+
if (sres < 0) \
|
22
|
+
rb_raise(rb_eRuntimeError, "Failed to sink data " #kind " %d.", sres); \
|
23
|
+
src.p += nread; \
|
24
|
+
src.n -= nread; \
|
25
|
+
} while (0);
|
26
|
+
|
27
|
+
// poll data from xcoder and append it to ruby string
|
28
|
+
#define HSRUBY_POLL_CAT(K, kind, hsx, str) \
|
29
|
+
HS##K##_poll_res pres; \
|
30
|
+
do { \
|
31
|
+
size_t nread; \
|
32
|
+
uint8_t buf[1024]; \
|
33
|
+
pres = heatshrink_##kind##_poll(hsx, buf, sizeof(buf), &nread); \
|
34
|
+
if (pres < 0) \
|
35
|
+
rb_raise(rb_eRuntimeError, "Failed to poll data %d.", pres); \
|
36
|
+
rb_str_cat(res, (char *)buf, nread); \
|
37
|
+
} while (pres == HS##K##R_POLL_MORE);
|
38
|
+
|
39
|
+
// finish xcoder
|
40
|
+
#define HSRUBY_FINISH(X, xcoder, hsx, res) \
|
41
|
+
HS##X##_finish_res fres; \
|
42
|
+
while (1) { \
|
43
|
+
fres = heatshrink_##xcoder##_finish(hsx); \
|
44
|
+
if (fres == HS##X##R_FINISH_DONE) \
|
45
|
+
break; \
|
46
|
+
if (fres < 0) \
|
47
|
+
rb_raise(rb_eRuntimeError, "Failed to finish %d.", fres); \
|
48
|
+
HSRUBY_POLL_CAT(X, xcoder, hsx, res); \
|
49
|
+
}
|
50
|
+
|
51
|
+
// alloc a decoder
|
52
|
+
#define HSRUBY_ALLOC_D(ibs, wsz2, lasz2) \
|
53
|
+
heatshrink_decoder_alloc(ibs, wsz2, lasz2)
|
54
|
+
// alloc an encoder
|
55
|
+
#define HSRUBY_ALLOC_E(ibs, wsz2, lasz2) heatshrink_encoder_alloc(wsz2, lasz2)
|
56
|
+
// free an xcoder
|
57
|
+
#define HSRUBY_FREE(X, xcoder, hsx) heatshrink_##xcoder##_free(hsx)
|
58
|
+
|
59
|
+
// encode/decode implementation
|
60
|
+
#define HSRUBY_IMPL(X, xcoder) \
|
61
|
+
Check_Type(data, T_STRING); \
|
62
|
+
Check_Type(window_sz2, T_FIXNUM); \
|
63
|
+
Check_Type(lookahead_sz2, T_FIXNUM); \
|
64
|
+
\
|
65
|
+
struct Buffer src = {(uint8_t *)RSTRING_PTR(data), RSTRING_LEN(data)}; \
|
66
|
+
VALUE res = rb_str_new(NULL, 0); \
|
67
|
+
\
|
68
|
+
int wsz2 = FIX2INT(window_sz2); \
|
69
|
+
int lasz2 = FIX2INT(lookahead_sz2); \
|
70
|
+
\
|
71
|
+
heatshrink_##xcoder *hsx = HSRUBY_ALLOC_##X(INPUT_BUFFER_SIZE, wsz2, lasz2); \
|
72
|
+
if (hsx == NULL) \
|
73
|
+
rb_raise(rb_eRuntimeError, "Failed to allocate " #xcoder "."); \
|
74
|
+
\
|
75
|
+
while (src.n) { \
|
76
|
+
HSRUBY_SINK(X, xcoder, src, hsx); \
|
77
|
+
HSRUBY_POLL_CAT(X, xcoder, hsx, res); \
|
78
|
+
} \
|
79
|
+
HSRUBY_FINISH(X, xcoder, hsx, res); \
|
80
|
+
HSRUBY_FREE(X, xcoder, hsx); \
|
81
|
+
return res;
|
82
|
+
|
83
|
+
static VALUE compress(VALUE self, VALUE data, VALUE window_sz2,
|
84
|
+
VALUE lookahead_sz2) {
|
85
|
+
HSRUBY_IMPL(E, encoder);
|
86
|
+
}
|
87
|
+
|
88
|
+
static VALUE uncompress(VALUE self, VALUE data, VALUE window_sz2,
|
89
|
+
VALUE lookahead_sz2) {
|
90
|
+
HSRUBY_IMPL(D, decoder);
|
91
|
+
}
|
92
|
+
|
93
|
+
void Init_heatshrink(void) {
|
94
|
+
VALUE mod = rb_define_module("Heatshrink");
|
95
|
+
mod = rb_define_module_under(mod, "Internal");
|
96
|
+
rb_define_module_function(mod, "compress", &compress, 3);
|
97
|
+
rb_define_module_function(mod, "uncompress", &uncompress, 3);
|
98
|
+
}
|
data/lib/heatshrink.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'heatshrink/heatshrink'
|
2
|
+
|
3
|
+
module Heatshrink
|
4
|
+
DEF_WINDOW_SZ2 = 11
|
5
|
+
DEF_LOOKAHEAD_SZ2 = 4
|
6
|
+
|
7
|
+
def self.compress data, window_sz2=DEF_WINDOW_SZ2, lookahead_sz2=DEF_LOOKAHEAD_SZ2
|
8
|
+
Internal.compress data, window_sz2, lookahead_sz2
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.uncompress data, window_sz2=DEF_WINDOW_SZ2, lookahead_sz2=DEF_LOOKAHEAD_SZ2
|
12
|
+
Internal.uncompress data, window_sz2, lookahead_sz2
|
13
|
+
end
|
14
|
+
end
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: heatshrink
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Scott Vokes
|
8
|
+
- Martin Nowak
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2017-02-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rake-compiler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - "~>"
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - "~>"
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
description:
|
29
|
+
email: code@dawg.eu
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/heatshrink/extconf.rb
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ext/heatshrink/extconf.rb
|
36
|
+
- ext/heatshrink/heatshrink_common.h
|
37
|
+
- ext/heatshrink/heatshrink_config.h
|
38
|
+
- ext/heatshrink/heatshrink_decoder.c
|
39
|
+
- ext/heatshrink/heatshrink_decoder.h
|
40
|
+
- ext/heatshrink/heatshrink_encoder.c
|
41
|
+
- ext/heatshrink/heatshrink_encoder.h
|
42
|
+
- ext/heatshrink/heatshrink_ruby.c
|
43
|
+
- lib/heatshrink.rb
|
44
|
+
homepage: http://github.com/MartinNowak/heatshrink-ruby
|
45
|
+
licenses:
|
46
|
+
- ICS
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 2.5.2
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: data compression library for embedded/real-time systems
|
68
|
+
test_files: []
|