arraybuffer 0.0.3
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/arraybuffer/arraybuffer.c +159 -0
- data/ext/arraybuffer/arraybuffer.h +11 -0
- data/ext/arraybuffer/arraybuffer_ext.c +14 -0
- data/ext/arraybuffer/dataview.c +467 -0
- data/ext/arraybuffer/dataview.h +13 -0
- data/ext/arraybuffer/extconf.rb +7 -0
- data/extconf.h +3 -0
- data/lib/arraybuffer.rb +1 -0
- metadata +67 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 19ea4341e8a445c5f0f7fb037201da95de458b1c598b19dfcdede555a7ada4af
|
4
|
+
data.tar.gz: 55c21ac531706d232aeb9997c214ea99124e5c5d72ca94266abcf91b47431408
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 761a077323636bb899b3c764f1b6225e0af328468d70a82a8d2cad42e70c585eeda68c6bbb8bf23c2ba3b80f495fc93402ef9b7e92cea77936d1e22a7a8b48fc
|
7
|
+
data.tar.gz: c1f26cdd5a15d3cb1068be495f8b1aee915b29a647fec7fc146420f0b39bf67a186a64b7b7fd52d58e744a380c3a5426ec0a906f0d71ac87313dca883093883a
|
@@ -0,0 +1,159 @@
|
|
1
|
+
#include "arraybuffer.h"
|
2
|
+
#include "extconf.h"
|
3
|
+
#include <string.h>
|
4
|
+
|
5
|
+
extern VALUE cArrayBuffer;
|
6
|
+
|
7
|
+
#define DECLAREBB(self) \
|
8
|
+
struct LLC_ArrayBuffer *bb = (struct LLC_ArrayBuffer*)rb_data_object_get((self))
|
9
|
+
|
10
|
+
#define CHECKBOUNDS(bb, idx) \
|
11
|
+
if (!(bb)->ptr || (idx) < 0 || (idx) >= (bb)->size) { \
|
12
|
+
rb_raise(rb_eArgError, "Index out of bounds: %d", (idx)); \
|
13
|
+
}
|
14
|
+
|
15
|
+
static void
|
16
|
+
t_bb_gc_mark(struct LLC_ArrayBuffer *bb) {
|
17
|
+
}
|
18
|
+
|
19
|
+
static void
|
20
|
+
t_bb_free(struct LLC_ArrayBuffer *bb) {
|
21
|
+
if (bb->ptr)
|
22
|
+
xfree(bb->ptr);
|
23
|
+
|
24
|
+
xfree(bb);
|
25
|
+
}
|
26
|
+
|
27
|
+
static VALUE
|
28
|
+
t_bb_allocator(VALUE klass) {
|
29
|
+
struct LLC_ArrayBuffer *bb = (struct LLC_ArrayBuffer*)xmalloc(sizeof(struct LLC_ArrayBuffer));
|
30
|
+
bb->ptr = NULL;
|
31
|
+
bb->size = 0;
|
32
|
+
|
33
|
+
return Data_Wrap_Struct(klass, t_bb_gc_mark, t_bb_free, bb);
|
34
|
+
}
|
35
|
+
|
36
|
+
static VALUE
|
37
|
+
t_bb_initialize(VALUE self, VALUE size) {
|
38
|
+
DECLAREBB(self);
|
39
|
+
unsigned int s = NUM2UINT(size);
|
40
|
+
bb->size = s;
|
41
|
+
if (bb->ptr)
|
42
|
+
xfree(bb->ptr);
|
43
|
+
bb->ptr = xmalloc(s);
|
44
|
+
memset(bb->ptr, 0, (size_t)s);
|
45
|
+
return self;
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE
|
49
|
+
t_bb_getbyte(VALUE self, VALUE index) {
|
50
|
+
DECLAREBB(self);
|
51
|
+
int idx = NUM2INT(index);
|
52
|
+
if (idx < 0)
|
53
|
+
idx += (int)bb->size;
|
54
|
+
CHECKBOUNDS(bb, idx);
|
55
|
+
return UINT2NUM((unsigned int)bb->ptr[idx]);
|
56
|
+
}
|
57
|
+
|
58
|
+
static VALUE
|
59
|
+
t_bb_setbyte(VALUE self, VALUE index, VALUE value) {
|
60
|
+
DECLAREBB(self);
|
61
|
+
int idx = NUM2INT(index);
|
62
|
+
unsigned int val = NUM2UINT(value);
|
63
|
+
if (idx < 0)
|
64
|
+
idx += (int)bb->size;
|
65
|
+
CHECKBOUNDS(bb, idx);
|
66
|
+
bb->ptr[idx] = (unsigned char)val;
|
67
|
+
return self;
|
68
|
+
}
|
69
|
+
|
70
|
+
static VALUE
|
71
|
+
t_bb_size(VALUE self) {
|
72
|
+
DECLAREBB(self);
|
73
|
+
return UINT2NUM(bb->size);
|
74
|
+
}
|
75
|
+
|
76
|
+
static VALUE
|
77
|
+
t_bb_each(VALUE self) {
|
78
|
+
DECLAREBB(self);
|
79
|
+
|
80
|
+
if (rb_block_given_p()) {
|
81
|
+
for (int i = 0; i < bb->size; i++) {
|
82
|
+
unsigned int val = (unsigned int)bb->ptr[i];
|
83
|
+
rb_yield(UINT2NUM(val));
|
84
|
+
}
|
85
|
+
} else {
|
86
|
+
rb_raise(rb_eArgError, "no block given");
|
87
|
+
}
|
88
|
+
|
89
|
+
return self;
|
90
|
+
}
|
91
|
+
|
92
|
+
static VALUE
|
93
|
+
t_bb_realloc(VALUE self, VALUE _new_size) {
|
94
|
+
DECLAREBB(self);
|
95
|
+
unsigned int new_size = NUM2UINT(_new_size);
|
96
|
+
if (new_size == bb->size)
|
97
|
+
return self;
|
98
|
+
|
99
|
+
void *old_ptr = (void*)bb->ptr;
|
100
|
+
if (new_size > 0) {
|
101
|
+
char *new_ptr = (void*)xmalloc(new_size);
|
102
|
+
if (old_ptr) {
|
103
|
+
if (new_size > bb->size) {
|
104
|
+
size_t diff = (size_t)(new_size - bb->size);
|
105
|
+
memcpy(new_ptr, old_ptr, (size_t)bb->size);
|
106
|
+
xfree(old_ptr);
|
107
|
+
old_ptr = NULL;
|
108
|
+
memset((char*)new_ptr + (size_t)bb->size, 0, diff);
|
109
|
+
} else {
|
110
|
+
memcpy(new_ptr, old_ptr, (size_t)new_size);
|
111
|
+
}
|
112
|
+
} else {
|
113
|
+
memset(new_ptr, 0, new_size);
|
114
|
+
}
|
115
|
+
bb->size = new_size;
|
116
|
+
bb->ptr = (unsigned char*)new_ptr;
|
117
|
+
} else {
|
118
|
+
bb->size = 0;
|
119
|
+
bb->ptr = NULL;
|
120
|
+
}
|
121
|
+
|
122
|
+
if (old_ptr)
|
123
|
+
xfree(old_ptr);
|
124
|
+
|
125
|
+
return self;
|
126
|
+
}
|
127
|
+
|
128
|
+
/*
|
129
|
+
* Returns a ASCII-8BIT string with the contents of the buffer
|
130
|
+
*
|
131
|
+
* The returned string is a copy of the buffer. It's encoding is always
|
132
|
+
* ASCII-8BIT.
|
133
|
+
* If the buffer has size zero, an empty string is returned.
|
134
|
+
*
|
135
|
+
* @return [String]
|
136
|
+
*/
|
137
|
+
static VALUE
|
138
|
+
t_bb_bytes(VALUE self) {
|
139
|
+
DECLAREBB(self);
|
140
|
+
return rb_tainted_str_new(
|
141
|
+
(const char*)bb->ptr,
|
142
|
+
bb->size);
|
143
|
+
}
|
144
|
+
|
145
|
+
void
|
146
|
+
Init_arraybuffer() {
|
147
|
+
cArrayBuffer = rb_define_class("ArrayBuffer", rb_cObject);
|
148
|
+
rb_define_alloc_func(cArrayBuffer, t_bb_allocator);
|
149
|
+
rb_include_module(cArrayBuffer, rb_mEnumerable);
|
150
|
+
|
151
|
+
rb_define_method(cArrayBuffer, "initialize", t_bb_initialize, 1);
|
152
|
+
rb_define_method(cArrayBuffer, "[]", t_bb_getbyte, 1);
|
153
|
+
rb_define_method(cArrayBuffer, "[]=", t_bb_setbyte, 2);
|
154
|
+
rb_define_method(cArrayBuffer, "size", t_bb_size, 0);
|
155
|
+
rb_define_alias(cArrayBuffer, "length", "size");
|
156
|
+
rb_define_method(cArrayBuffer, "each", t_bb_each, 0);
|
157
|
+
rb_define_method(cArrayBuffer, "realloc", t_bb_realloc, 1);
|
158
|
+
rb_define_method(cArrayBuffer, "bytes", t_bb_bytes, 0);
|
159
|
+
}
|
@@ -0,0 +1,467 @@
|
|
1
|
+
#include "dataview.h"
|
2
|
+
#include "arraybuffer.h"
|
3
|
+
#include "extconf.h"
|
4
|
+
|
5
|
+
#ifdef HAVE_STRING_H
|
6
|
+
#include <string.h>
|
7
|
+
#endif
|
8
|
+
|
9
|
+
extern VALUE cArrayBuffer;
|
10
|
+
extern VALUE cDataView;
|
11
|
+
|
12
|
+
static ID idEndianess = Qundef;
|
13
|
+
static ID idBig = Qundef;
|
14
|
+
static ID idLittle = Qundef;
|
15
|
+
|
16
|
+
#define FLAG_LITTLE_ENDIAN 1
|
17
|
+
|
18
|
+
#define DECLAREDV(o) \
|
19
|
+
struct LLC_DataView *dv = (struct LLC_DataView*)rb_data_object_get((o))
|
20
|
+
#define DECLAREBB(o) \
|
21
|
+
struct LLC_ArrayBuffer *bb = (struct LLC_ArrayBuffer*)rb_data_object_get((o))
|
22
|
+
#define CHECK_LITTLEENDIAN(dv) ((dv)->flags & FLAG_LITTLE_ENDIAN)
|
23
|
+
|
24
|
+
static void
|
25
|
+
t_dv_gc_mark(struct LLC_DataView *dv) {
|
26
|
+
if (dv->bb_obj)
|
27
|
+
rb_gc_mark(dv->bb_obj);
|
28
|
+
}
|
29
|
+
|
30
|
+
static void
|
31
|
+
t_dv_free(struct LLC_DataView *dv) {
|
32
|
+
xfree(dv);
|
33
|
+
}
|
34
|
+
|
35
|
+
static VALUE
|
36
|
+
t_dv_allocator(VALUE klass) {
|
37
|
+
struct LLC_DataView *dv = (struct LLC_DataView*)xmalloc(sizeof(struct LLC_DataView));
|
38
|
+
dv->bb_obj = Qundef;
|
39
|
+
dv->size = 0;
|
40
|
+
dv->offset = 0;
|
41
|
+
dv->flags = 0;
|
42
|
+
return Data_Wrap_Struct(klass, t_dv_gc_mark, t_dv_free, dv);
|
43
|
+
}
|
44
|
+
|
45
|
+
/*
|
46
|
+
* call-seq:
|
47
|
+
* initialize(buffer, offset, size, endianess:)
|
48
|
+
*
|
49
|
+
* Constructs a new DataView that provides a view of the data in a ArrayBuffer.
|
50
|
+
*
|
51
|
+
* Example:
|
52
|
+
* buffer = ArrayBuffer.new(10)
|
53
|
+
* buffer[1] = 20
|
54
|
+
* buffer[2] = 55
|
55
|
+
* view = DataView.new(buffer, 1, endianess: :little)
|
56
|
+
* view.getU8() == ( 20 & (55 << 8) ) # true
|
57
|
+
*
|
58
|
+
* Or:
|
59
|
+
*
|
60
|
+
* view = DataView.new(buffer, 1) # default endianess is "big endian"
|
61
|
+
* view.getU8() == ( (20 << 8) | 55 ) # true
|
62
|
+
*
|
63
|
+
* @param buffer [ArrayBuffer] The array buffer where to operate
|
64
|
+
* @param offset [Integer] Optional. The byte offset from the array buffer. The
|
65
|
+
* default value is zero
|
66
|
+
* @param size [Integer] Optional. The size in bytes that this DataView can
|
67
|
+
* see into the array buffer. If left blank, the current size of the array
|
68
|
+
* buffer will be used
|
69
|
+
* @param endianess [:big, :little] Optional. The default value is big
|
70
|
+
*
|
71
|
+
*/
|
72
|
+
static VALUE
|
73
|
+
t_dv_initialize(int argc, VALUE *argv, VALUE self) {
|
74
|
+
DECLAREDV(self);
|
75
|
+
VALUE bb_obj;
|
76
|
+
VALUE offset;
|
77
|
+
VALUE size;
|
78
|
+
VALUE kwargs;
|
79
|
+
static ID keyword_ids[] = { 0 };
|
80
|
+
|
81
|
+
rb_scan_args(argc, argv, "12:", &bb_obj, &offset, &size, &kwargs);
|
82
|
+
|
83
|
+
DECLAREBB(bb_obj);
|
84
|
+
|
85
|
+
int size_val = NIL_P(size) ? (int)bb->size : NUM2INT(size);
|
86
|
+
if (size_val < 0)
|
87
|
+
size_val += (int)bb->size;
|
88
|
+
if (size_val < 0)
|
89
|
+
rb_raise(rb_eArgError, "calculated size is negative: %d", size_val);
|
90
|
+
|
91
|
+
int offset_val = NIL_P(offset) ? 0 : NUM2INT(offset);
|
92
|
+
if (offset_val < 0)
|
93
|
+
offset_val += (int)bb->size;
|
94
|
+
if (offset_val < 0)
|
95
|
+
rb_raise(rb_eArgError, "calculated offset is negative: %d", offset_val);
|
96
|
+
|
97
|
+
dv->offset = (unsigned long)offset_val;
|
98
|
+
dv->size = (unsigned long)size_val;
|
99
|
+
dv->bb_obj = bb_obj;
|
100
|
+
|
101
|
+
if (!keyword_ids[0]) {
|
102
|
+
keyword_ids[0] = idEndianess;
|
103
|
+
}
|
104
|
+
|
105
|
+
if (!NIL_P(kwargs)) {
|
106
|
+
VALUE endianess;
|
107
|
+
rb_get_kwargs(kwargs, keyword_ids, 0, 1, &endianess);
|
108
|
+
if (endianess != Qundef) {
|
109
|
+
Check_Type(endianess, T_SYMBOL);
|
110
|
+
ID id = SYM2ID(endianess);
|
111
|
+
if (id == idLittle)
|
112
|
+
dv->flags |= FLAG_LITTLE_ENDIAN;
|
113
|
+
else if (id != idBig)
|
114
|
+
rb_raise(rb_eArgError, "endianess must be either :big or :little");
|
115
|
+
}
|
116
|
+
}
|
117
|
+
|
118
|
+
return self;
|
119
|
+
}
|
120
|
+
|
121
|
+
static VALUE
|
122
|
+
t_dv_size(VALUE self) {
|
123
|
+
DECLAREDV(self);
|
124
|
+
return UINT2NUM(dv->size);
|
125
|
+
}
|
126
|
+
|
127
|
+
static VALUE
|
128
|
+
t_dv_offset(VALUE self) {
|
129
|
+
DECLAREDV(self);
|
130
|
+
return UINT2NUM(dv->offset);
|
131
|
+
}
|
132
|
+
|
133
|
+
static VALUE
|
134
|
+
t_dv_endianess(VALUE self) {
|
135
|
+
DECLAREDV(self);
|
136
|
+
return CHECK_LITTLEENDIAN(dv) ?
|
137
|
+
ID2SYM(idLittle) :
|
138
|
+
ID2SYM(idBig);
|
139
|
+
}
|
140
|
+
|
141
|
+
static VALUE
|
142
|
+
t_dv_each(VALUE self) {
|
143
|
+
DECLAREDV(self);
|
144
|
+
DECLAREBB(dv->bb_obj);
|
145
|
+
|
146
|
+
int size = dv->size;
|
147
|
+
if (size + dv->offset >= bb->size)
|
148
|
+
size = bb->size - dv->offset;
|
149
|
+
|
150
|
+
if (rb_block_given_p()) {
|
151
|
+
for (int i = 0; i < size; i++) {
|
152
|
+
unsigned int val = (unsigned int)bb->ptr[i + dv->offset];
|
153
|
+
rb_yield(UINT2NUM(val));
|
154
|
+
}
|
155
|
+
} else {
|
156
|
+
rb_raise(rb_eArgError, "no block given");
|
157
|
+
}
|
158
|
+
return self;
|
159
|
+
}
|
160
|
+
|
161
|
+
/*
|
162
|
+
* Defined the new offset for the DataView.
|
163
|
+
*
|
164
|
+
* Changing the offset does not affect the size.
|
165
|
+
* If passed a negative value, it will be summed with the underlying buffer
|
166
|
+
* size. The final value must not be lower than zero.
|
167
|
+
*
|
168
|
+
* @param offset [Integer] The new offset
|
169
|
+
*/
|
170
|
+
static VALUE
|
171
|
+
t_dv_setoffset(VALUE self, VALUE offset) {
|
172
|
+
DECLAREDV(self);
|
173
|
+
DECLAREBB(dv->bb_obj);
|
174
|
+
int offset_val = NIL_P(offset) ? 0 : NUM2INT(offset);
|
175
|
+
if (offset_val < 0)
|
176
|
+
offset_val += (int)bb->size;
|
177
|
+
if (offset_val < 0)
|
178
|
+
rb_raise(rb_eArgError, "calculated offset is negative: %d", offset_val);
|
179
|
+
|
180
|
+
dv->offset = (unsigned long)offset_val;
|
181
|
+
return self;
|
182
|
+
}
|
183
|
+
|
184
|
+
/*
|
185
|
+
* Defined the new offset for the DataView.
|
186
|
+
*
|
187
|
+
* Changing the size does not affect the offset.
|
188
|
+
* If passed a negative value, it will be summed with the underlying buffer
|
189
|
+
* size. The final value must not be lower than zero.
|
190
|
+
*
|
191
|
+
* @param size [Integer] The new size. Must be zero or greater
|
192
|
+
*/
|
193
|
+
static VALUE
|
194
|
+
t_dv_setsize(VALUE self, VALUE size) {
|
195
|
+
DECLAREDV(self);
|
196
|
+
DECLAREBB(dv->bb_obj);
|
197
|
+
int size_val = NIL_P(size) ? (int)bb->size : NUM2INT(size);
|
198
|
+
if (size_val < 0)
|
199
|
+
size_val += (int)bb->size;
|
200
|
+
if (size_val < 0)
|
201
|
+
rb_raise(rb_eArgError, "calculated size is negative: %d", size_val);
|
202
|
+
|
203
|
+
dv->size = (unsigned long)size_val;
|
204
|
+
return self;
|
205
|
+
}
|
206
|
+
|
207
|
+
#define DECLARENCHECKIDX(index) int idx = NUM2INT(index); \
|
208
|
+
if (idx < 0) idx += (int)dv->size; \
|
209
|
+
if (idx < 0 || idx >= dv->size) rb_raise(rb_eArgError, "index out of bounds: %d", idx);
|
210
|
+
|
211
|
+
#define CHECKBOUNDSBB(v) if ((v) < 0 || (v) >= (bb)->size) \
|
212
|
+
rb_raise(rb_eArgError, "index out of underlying buffer bounds: %d", (v));
|
213
|
+
|
214
|
+
/*
|
215
|
+
* Reads a bit at index.
|
216
|
+
*
|
217
|
+
* This method differs from the other in that the +index+ is given in bits, not
|
218
|
+
* in bytes.
|
219
|
+
* Thus it's possible to read from index +0+ to +(size * 8) - 1+
|
220
|
+
*
|
221
|
+
* @return [Integer] Either 0 or 1
|
222
|
+
*/
|
223
|
+
static VALUE
|
224
|
+
t_dv_getbit(VALUE self, VALUE index) {
|
225
|
+
DECLAREDV(self); DECLAREBB(dv->bb_obj);
|
226
|
+
int idx = NUM2INT(index);
|
227
|
+
if (idx < 0)
|
228
|
+
idx += (int)dv->size * 8;
|
229
|
+
if (idx < 0 || idx >= dv->size * 8)
|
230
|
+
rb_raise(rb_eArgError, "index out of bounds: %d", idx);
|
231
|
+
|
232
|
+
unsigned int bit_idx = ((unsigned int)idx) & 7;
|
233
|
+
unsigned int byte_idx = (((unsigned int)idx) >> 3) + dv->offset;
|
234
|
+
unsigned char bit_mask = 1 << bit_idx;
|
235
|
+
|
236
|
+
CHECKBOUNDSBB(byte_idx);
|
237
|
+
return (bb->ptr[byte_idx] & bit_mask) ? UINT2NUM(1) : UINT2NUM(0);
|
238
|
+
}
|
239
|
+
|
240
|
+
/*
|
241
|
+
* Reads the byte at index as an +unsigned char+
|
242
|
+
*
|
243
|
+
* @return [Integer] Integer between 0 and 255
|
244
|
+
*/
|
245
|
+
static VALUE
|
246
|
+
t_dv_getu8(VALUE self, VALUE index) {
|
247
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
248
|
+
unsigned int real_idx = dv->offset + (unsigned int)idx;
|
249
|
+
CHECKBOUNDSBB(real_idx);
|
250
|
+
return UINT2NUM(bb->ptr[real_idx]);
|
251
|
+
}
|
252
|
+
|
253
|
+
/*
|
254
|
+
* Reads two bytes starting at index as an +unsigned short+
|
255
|
+
*
|
256
|
+
* @return [Integer] Integer between 0 and 65535
|
257
|
+
*/
|
258
|
+
static VALUE
|
259
|
+
t_dv_getu16(VALUE self, VALUE index) {
|
260
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
261
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
262
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
263
|
+
CHECKBOUNDSBB(idx0);
|
264
|
+
CHECKBOUNDSBB(idx1);
|
265
|
+
unsigned short val = 0;
|
266
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
267
|
+
val |= bb->ptr[idx0];
|
268
|
+
val |= bb->ptr[idx1] << 8;
|
269
|
+
} else {
|
270
|
+
val |= bb->ptr[idx0] << 8;
|
271
|
+
val |= bb->ptr[idx1];
|
272
|
+
}
|
273
|
+
return UINT2NUM(val);
|
274
|
+
}
|
275
|
+
|
276
|
+
/*
|
277
|
+
* Reads three bytes starting at index as a 3 bytes long unsigned integer
|
278
|
+
*
|
279
|
+
* @return [Integer] Integer between 0 and 16777215
|
280
|
+
*/
|
281
|
+
static VALUE
|
282
|
+
t_dv_getu24(VALUE self, VALUE index) {
|
283
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
284
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
285
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
286
|
+
unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
|
287
|
+
CHECKBOUNDSBB(idx0);
|
288
|
+
CHECKBOUNDSBB(idx2);
|
289
|
+
unsigned int val = 0;
|
290
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
291
|
+
val |= bb->ptr[idx0];
|
292
|
+
val |= bb->ptr[idx1] << 8;
|
293
|
+
val |= bb->ptr[idx2] << 16;
|
294
|
+
} else {
|
295
|
+
val |= bb->ptr[idx0] << 16;
|
296
|
+
val |= bb->ptr[idx1] << 8;
|
297
|
+
val |= bb->ptr[idx2];
|
298
|
+
}
|
299
|
+
return UINT2NUM(val);
|
300
|
+
}
|
301
|
+
|
302
|
+
/*
|
303
|
+
* Reads four bytes starting at index as a 4 bytes long unsigned integer
|
304
|
+
*
|
305
|
+
* @return [Integer] Integer between 0 and 4294967295
|
306
|
+
*/
|
307
|
+
static VALUE
|
308
|
+
t_dv_getu32(VALUE self, VALUE index) {
|
309
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
310
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
311
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
312
|
+
unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
|
313
|
+
unsigned int idx3 = dv->offset + (unsigned int)idx + 3;
|
314
|
+
CHECKBOUNDSBB(idx0);
|
315
|
+
CHECKBOUNDSBB(idx3);
|
316
|
+
unsigned int val = 0;
|
317
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
318
|
+
val |= bb->ptr[idx0];
|
319
|
+
val |= bb->ptr[idx1] << 8;
|
320
|
+
val |= bb->ptr[idx2] << 16;
|
321
|
+
val |= bb->ptr[idx3] << 24;
|
322
|
+
} else {
|
323
|
+
val |= bb->ptr[idx0] << 24;
|
324
|
+
val |= bb->ptr[idx1] << 16;
|
325
|
+
val |= bb->ptr[idx2] << 8;
|
326
|
+
val |= bb->ptr[idx3];
|
327
|
+
}
|
328
|
+
return UINT2NUM(val);
|
329
|
+
}
|
330
|
+
|
331
|
+
#define ADJUSTBOUNDS(val, max) if (val < 0) val = 0; else if (val > max) val = max;
|
332
|
+
|
333
|
+
/*
|
334
|
+
* Interprets one byte at index and assigns it an unsigned value
|
335
|
+
*
|
336
|
+
* Values lower than zero will be set to 0 and values greater than 255
|
337
|
+
* will be capped.
|
338
|
+
*/
|
339
|
+
static VALUE
|
340
|
+
t_dv_setu8(VALUE self, VALUE index, VALUE value) {
|
341
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
342
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
343
|
+
CHECKBOUNDSBB(idx0);
|
344
|
+
int val = NUM2INT(value);
|
345
|
+
ADJUSTBOUNDS(val, 0xFF);
|
346
|
+
bb->ptr[idx0] = (unsigned char)val;
|
347
|
+
return self;
|
348
|
+
}
|
349
|
+
|
350
|
+
/*
|
351
|
+
* Interprets two bytes starting at index and sets them an unsigned value
|
352
|
+
*
|
353
|
+
* Values lower than zero will be set to 0 and values greater than 65535
|
354
|
+
* will be capped.
|
355
|
+
*/
|
356
|
+
static VALUE
|
357
|
+
t_dv_setu16(VALUE self, VALUE index, VALUE value) {
|
358
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
359
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
360
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
361
|
+
CHECKBOUNDSBB(idx0);
|
362
|
+
CHECKBOUNDSBB(idx1);
|
363
|
+
int val = NUM2INT(value);
|
364
|
+
ADJUSTBOUNDS(val, 0xFFFF);
|
365
|
+
unsigned int uval = (unsigned int)val;
|
366
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
367
|
+
bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
|
368
|
+
bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
|
369
|
+
} else {
|
370
|
+
bb->ptr[idx0] = (unsigned char)((uval >> 8) & 0xFF);
|
371
|
+
bb->ptr[idx1] = (unsigned char)(uval & 0xFF);
|
372
|
+
}
|
373
|
+
return self;
|
374
|
+
}
|
375
|
+
|
376
|
+
/*
|
377
|
+
* Interprets three bytes starting at index and sets them an unsigned value
|
378
|
+
*
|
379
|
+
* Values lower than zero will be set to 0 and values greater than 16777215
|
380
|
+
* will be capped.
|
381
|
+
*/
|
382
|
+
static VALUE
|
383
|
+
t_dv_setu24(VALUE self, VALUE index, VALUE value) {
|
384
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
385
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
386
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
387
|
+
unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
|
388
|
+
CHECKBOUNDSBB(idx0);
|
389
|
+
CHECKBOUNDSBB(idx2);
|
390
|
+
int val = NUM2INT(value);
|
391
|
+
ADJUSTBOUNDS(val, 0xFFFFFF);
|
392
|
+
unsigned int uval = (unsigned int)val;
|
393
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
394
|
+
bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
|
395
|
+
bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
|
396
|
+
bb->ptr[idx2] = (unsigned char)((uval >> 16) & 0xFF);
|
397
|
+
} else {
|
398
|
+
bb->ptr[idx0] = (unsigned char)((uval >> 16) & 0xFF);
|
399
|
+
bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
|
400
|
+
bb->ptr[idx2] = (unsigned char)(uval & 0xFF);
|
401
|
+
}
|
402
|
+
return self;
|
403
|
+
}
|
404
|
+
|
405
|
+
/*
|
406
|
+
* Interprets four bytes starting at index and sets them an unsigned value
|
407
|
+
*
|
408
|
+
* Values lower than zero will be set to 0 and values greater than 4294967295
|
409
|
+
* will be capped.
|
410
|
+
*/
|
411
|
+
static VALUE
|
412
|
+
t_dv_setu32(VALUE self, VALUE index, VALUE value) {
|
413
|
+
DECLAREDV(self); DECLARENCHECKIDX(index); DECLAREBB(dv->bb_obj);
|
414
|
+
unsigned int idx0 = dv->offset + (unsigned int)idx;
|
415
|
+
unsigned int idx1 = dv->offset + (unsigned int)idx + 1;
|
416
|
+
unsigned int idx2 = dv->offset + (unsigned int)idx + 2;
|
417
|
+
unsigned int idx3 = dv->offset + (unsigned int)idx + 3;
|
418
|
+
CHECKBOUNDSBB(idx0);
|
419
|
+
CHECKBOUNDSBB(idx3);
|
420
|
+
long val = NUM2LONG(value);
|
421
|
+
ADJUSTBOUNDS(val, 0xFFFFFFFF);
|
422
|
+
unsigned long uval = (unsigned long)val;
|
423
|
+
if (CHECK_LITTLEENDIAN(dv)) {
|
424
|
+
bb->ptr[idx0] = (unsigned char)(uval & 0xFF);
|
425
|
+
bb->ptr[idx1] = (unsigned char)((uval >> 8) & 0xFF);
|
426
|
+
bb->ptr[idx2] = (unsigned char)((uval >> 16) & 0xFF);
|
427
|
+
bb->ptr[idx3] = (unsigned char)((uval >> 24) & 0xFF);
|
428
|
+
} else {
|
429
|
+
bb->ptr[idx0] = (unsigned char)((uval >> 24) & 0xFF);
|
430
|
+
bb->ptr[idx1] = (unsigned char)((uval >> 16) & 0xFF);
|
431
|
+
bb->ptr[idx2] = (unsigned char)((uval >> 8) & 0xFF);
|
432
|
+
bb->ptr[idx3] = (unsigned char)(uval & 0xFF);
|
433
|
+
}
|
434
|
+
return self;
|
435
|
+
}
|
436
|
+
|
437
|
+
void
|
438
|
+
Init_dataview() {
|
439
|
+
idEndianess = rb_intern("endianess");
|
440
|
+
idLittle = rb_intern("little");
|
441
|
+
idBig = rb_intern("big");
|
442
|
+
|
443
|
+
cDataView = rb_define_class("DataView", rb_cObject);
|
444
|
+
rb_define_alloc_func(cDataView, t_dv_allocator);
|
445
|
+
rb_include_module(cDataView, rb_mEnumerable);
|
446
|
+
|
447
|
+
rb_define_method(cDataView, "initialize", t_dv_initialize, -1);
|
448
|
+
rb_define_method(cDataView, "getBit", t_dv_getbit, 1);
|
449
|
+
rb_define_method(cDataView, "getU8", t_dv_getu8, 1);
|
450
|
+
rb_define_method(cDataView, "getU16", t_dv_getu16, 1);
|
451
|
+
rb_define_method(cDataView, "getU24", t_dv_getu24, 1);
|
452
|
+
rb_define_method(cDataView, "getU32", t_dv_getu32, 1);
|
453
|
+
|
454
|
+
rb_define_method(cDataView, "setU8", t_dv_setu8, 2);
|
455
|
+
rb_define_method(cDataView, "setU16", t_dv_setu16, 2);
|
456
|
+
rb_define_method(cDataView, "setU24", t_dv_setu24, 2);
|
457
|
+
rb_define_method(cDataView, "setU32", t_dv_setu32, 2);
|
458
|
+
|
459
|
+
rb_define_method(cDataView, "endianess", t_dv_endianess, 0);
|
460
|
+
rb_define_method(cDataView, "offset=", t_dv_setoffset, 1);
|
461
|
+
rb_define_method(cDataView, "offset", t_dv_offset, 0);
|
462
|
+
rb_define_method(cDataView, "size=", t_dv_setsize, 1);
|
463
|
+
rb_define_alias(cDataView, "length=", "size=");
|
464
|
+
rb_define_method(cDataView, "size", t_dv_size, 0);
|
465
|
+
rb_define_alias(cDataView, "length", "size");
|
466
|
+
rb_define_method(cDataView, "each", t_dv_each, 0);
|
467
|
+
}
|
data/extconf.h
ADDED
data/lib/arraybuffer.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "arraybuffer_ext"
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: arraybuffer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- André Diego Piske
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-03-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.9'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.9'
|
27
|
+
description:
|
28
|
+
email:
|
29
|
+
- andrepiske@gmail.com
|
30
|
+
executables: []
|
31
|
+
extensions:
|
32
|
+
- ext/arraybuffer/extconf.rb
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ext/arraybuffer/arraybuffer.c
|
36
|
+
- ext/arraybuffer/arraybuffer.h
|
37
|
+
- ext/arraybuffer/arraybuffer_ext.c
|
38
|
+
- ext/arraybuffer/dataview.c
|
39
|
+
- ext/arraybuffer/dataview.h
|
40
|
+
- ext/arraybuffer/extconf.rb
|
41
|
+
- extconf.h
|
42
|
+
- lib/arraybuffer.rb
|
43
|
+
homepage: https://github.com/andrepiske/rb-arraybuffer
|
44
|
+
licenses:
|
45
|
+
- MIT
|
46
|
+
metadata:
|
47
|
+
source_code_uri: https://github.com/andrepiske/rb-arraybuffer
|
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: '2.1'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubygems_version: 3.1.2
|
64
|
+
signing_key:
|
65
|
+
specification_version: 4
|
66
|
+
summary: Low level byte operators and buffers
|
67
|
+
test_files: []
|