/
binary.cc
327 lines (266 loc) · 11.1 KB
/
binary.cc
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <v8.h>
#include <node.h>
#include <node_version.h>
#include <node_events.h>
#include <node_buffer.h>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <iostream>
#include <limits>
#include "binary.h"
#define MIN(a,b) ((a) < (b) ? (a) : (b))
const uint32_t BSON_BINARY_SUBTYPE_DEFAULT = 0;
const uint32_t BSON_BINARY_SUBTYPE_FUNCTION = 1;
const uint32_t BSON_BINARY_SUBTYPE_BYTE_ARRAY = 2;
const uint32_t BSON_BINARY_SUBTYPE_UUID = 3;
const uint32_t BSON_BINARY_SUBTYPE_MD5 = 4;
const uint32_t BSON_BINARY_SUBTYPE_USER_DEFINED = 128;
static Handle<Value> VException(const char *msg) {
HandleScope scope;
return ThrowException(Exception::Error(String::New(msg)));
};
Persistent<FunctionTemplate> Binary::constructor_template;
Binary::Binary(uint32_t sub_type, uint32_t number_of_bytes, uint32_t index, char *data) : ObjectWrap() {
this->sub_type = sub_type;
this->number_of_bytes = number_of_bytes;
this->index = index;
this->data = data;
}
Binary::~Binary() {
free(this->data);
}
Handle<Value> Binary::New(const Arguments &args) {
HandleScope scope;
Binary *binary;
if(args.Length() > 2) {
return VException("Argument must be either none, a string or a sub_type and string");
}
if(args.Length() == 0) {
char *oid_string_bytes = (char *)malloc(256);
*(oid_string_bytes) = '\0';
binary = new Binary(BSON_BINARY_SUBTYPE_DEFAULT, 256, 0, oid_string_bytes);
} else if(args.Length() == 1 && args[0]->IsString()) {
Local<String> str = args[0]->ToString();
// Contains the bytes for the data
char *oid_string_bytes = (char *)malloc(str->Length() + 1);
*(oid_string_bytes + str->Length()) = '\0';
// Decode the data from the string
node::DecodeWrite(oid_string_bytes, str->Length(), str, node::BINARY);
// Create a binary object
binary = new Binary(BSON_BINARY_SUBTYPE_DEFAULT, str->Length(), str->Length(), oid_string_bytes);
} else if(args.Length() == 2 && args[1]->IsNumber() && args[0]->IsString()) {
Local<String> str = args[0]->ToString();
Local<Integer> intr = args[1]->ToInteger();
// Contains the bytes for the data
char *oid_string_bytes = (char *)malloc(str->Length() + 1);
*(oid_string_bytes + str->Length()) = '\0';
// Decode the data from the string
node::DecodeWrite(oid_string_bytes, str->Length(), str, node::BINARY);
// Decode the subtype
uint32_t sub_type = intr->Uint32Value();
binary = new Binary(sub_type, str->Length(), str->Length(), oid_string_bytes);
} else {
return VException("Argument must be either none, a string or a string and a sub_type");
}
// Wrap it
binary->Wrap(args.This());
// Return the object
return args.This();
}
static Persistent<String> subtype_symbol;
void Binary::Initialize(Handle<Object> target) {
// Grab the scope of the call from Node
HandleScope scope;
// Define a new function template
Local<FunctionTemplate> t = FunctionTemplate::New(New);
constructor_template = Persistent<FunctionTemplate>::New(t);
constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
constructor_template->SetClassName(String::NewSymbol("Binary"));
// Propertry symbols
subtype_symbol = NODE_PSYMBOL("sub_type");
// Instance methods
NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "inspect", Inspect);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "value", Data);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "length", Length);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "put", Put);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "write", Write);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "read", Read);
NODE_SET_PROTOTYPE_METHOD(constructor_template, "readInto", ReadInto);
// Getters for correct serialization of the object
constructor_template->InstanceTemplate()->SetAccessor(subtype_symbol, SubtypeGetter, SubtypeSetter);
target->Set(String::NewSymbol("Binary"), constructor_template->GetFunction());
}
Handle<Value> Binary::SubtypeGetter(Local<String> property, const AccessorInfo& info) {
HandleScope scope;
// Unpack object reference
Binary *binary_obj = ObjectWrap::Unwrap<Binary>(info.Holder());
// Extract value doing a cast of the pointer to Long and accessing low_bits
Local<Integer> sub_type_int = Integer::New(binary_obj->sub_type);
return scope.Close(sub_type_int);
}
void Binary::SubtypeSetter(Local<String> property, Local<Value> value, const AccessorInfo& info) {
if(value->IsNumber()) {
// Unpack the long object
Binary *b = ObjectWrap::Unwrap<Binary>(info.Holder());
// Set the low bits
b->sub_type = value->IntegerValue();
}
}
Handle<Value> Binary::Read(const Arguments &args) {
HandleScope scope;
// Ensure we have the right parameters
if(args.Length() != 2 && !args[0]->IsUint32() && !args[1]->IsUint32()) return VException("Function takes two arguments of type Integer, position and offset");
// Let's unpack the parameters
uint32_t position = args[0]->Uint32Value();
uint32_t length = args[1]->Uint32Value();
// Let's unpack the binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Ensure that it's a valid range
if(binary->number_of_bytes >= position && binary->number_of_bytes >= (position + length)) {
// Decode the data
Local<String> encoded_data = Encode((binary->data + position), length, BINARY)->ToString();
// Return the data to the client
return scope.Close(encoded_data);
} else {
return VException("position and length is outside the size of the binary");
}
}
Handle<Value> Binary::ReadInto(const Arguments &args) {
HandleScope scope;
if (args.Length() == 0 || !Buffer::HasInstance(args[0])) {
return VException("Function takes at least one argument of type Buffer");
}
size_t offset = args[1]->IsUint32() ? args[1]->Uint32Value() : 0;
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
if (binary->index - offset < 0) {
return VException("offset argument out of bounds");
}
Local<Object> obj = args[0]->ToObject();
size_t blength = Buffer::Length(obj);
char *data = Buffer::Data(obj);
size_t towrite = MIN(blength, binary->index - offset);
if (towrite > 0) {
memmove(data, binary->data + offset, towrite);
}
return scope.Close(Integer::New(towrite));
}
Handle<Value> Binary::Write(const Arguments &args) {
HandleScope scope;
// Ensure we have the right parameters
if(args.Length() == 1 && (!args[0]->IsString() || Buffer::HasInstance(args[0]))) return VException("Function takes one argument of type String or Buffer");
if(args.Length() == 2 && (!args[0]->IsString() || Buffer::HasInstance(args[0])) && !args[1]->IsUint32()) return VException("Function takes one argument of type String or Buffer");
// Reference variables
char *data;
uint32_t length;
uint32_t offset = 0;
Local<Object> obj = args[0]->ToObject();
// Unpack the offset value
if(args.Length() == 2) {
offset = args[1]->ToUint32()->Value();
}
// If we have a buffer let's retrieve the data
if(Buffer::HasInstance(obj)) {
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION < 3
Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
data = buffer->data();
length = buffer->length();
#else
data = Buffer::Data(obj);
length = Buffer::Length(obj);
#endif
} else {
Local<String> str = args[0]->ToString();
length = DecodeBytes(str, BINARY);
data = (char *)malloc(length * sizeof(char));
uint32_t written = DecodeWrite(data, length, str, BINARY);
assert(length == written);
}
// Ensure we got enough allocated space for the content
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Check if we have enough space or we need to allocate more space
if((binary->index + length) > binary->number_of_bytes) {
// Realocate memory (and add double the current space to allow for more writing)
binary->data = (char *)realloc(binary->data, ((binary->number_of_bytes * 2) + length));
binary->number_of_bytes = (binary->number_of_bytes * 2) + length;
}
// If no offset specified use internal index
if(offset == 0) offset = binary->index;
// Write the element out
memcpy((binary->data + offset), data, length);
// Update the index pointer
binary->index = offset + length;
// free the memory if we have allocated
if(!Buffer::HasInstance(args[0])) {
free(data);
}
// Close and return
return scope.Close(Null());
}
Handle<Value> Binary::Put(const Arguments &args) {
HandleScope scope;
// Ensure we have the right parameters
if(args.Length() != 1 && !args[0]->IsString()) return VException("Function takes one argument of type String containing one character");
// Unpack the character (string)
Local<String> str = args[0]->ToString();
// Let's unpack the string to char
ssize_t len = DecodeBytes(str, BINARY);
if(len != 1) return VException("Function takes one argument of type String containing one character");
// Let's define the buffer that contains the regexp string
// char *data = new char[len + 1];
char *data = (char *)malloc(len * sizeof(char) + 1);
// Write the data to the buffer from the string object
ssize_t written = DecodeWrite(data, len, str, BINARY);
// Unpack the binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Check if we need to adjust the size of the binary to fit more space
if((binary->index + len) > binary->number_of_bytes) {
// Realocate memory (and double the allocated space 256-512-1024-2048-4096) to try to lower
// the number of times we reallocate memory
binary->data = (char *)realloc(binary->data, binary->number_of_bytes * 2);
binary->number_of_bytes = binary->number_of_bytes * 2;
}
// Write the element out
*(binary->data + binary->index) = *(data);
// Update the index pointer
binary->index = binary->index + 1;
// Free up the data
// delete data;
free(data);
// Return a null
return scope.Close(Null());
}
Handle<Value> Binary::Length(const Arguments &args) {
HandleScope scope;
// Unpack the Binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
return scope.Close(Integer::New(binary->index));
}
Handle<Value> Binary::Data(const Arguments &args) {
HandleScope scope;
// Unpack the Binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Return the raw data
Local<Value> bin_value = Encode(binary->data, binary->index, BINARY);
return scope.Close(bin_value);
}
Handle<Value> Binary::Inspect(const Arguments &args) {
HandleScope scope;
// Unpack the Binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Return the raw data
Local<Value> bin_value = Encode(binary->data, binary->number_of_bytes, BINARY);
return scope.Close(bin_value);
}
Handle<Value> Binary::ToString(const Arguments &args) {
HandleScope scope;
// Unpack the Binary object
Binary *binary = ObjectWrap::Unwrap<Binary>(args.This());
// Return the raw data
Local<Value> bin_value = Encode(binary->data, binary->number_of_bytes, BINARY);
return scope.Close(bin_value);
}