Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 793 lines (599 sloc) 23.651 kb
55048cd @ry Update copyright headers
ry authored
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21
e0f47be @piscisaureus Clean up the way windows headers are included
piscisaureus authored
22
23 #include <node.h>
469e264 @ry More bindings, beginning tcp server code in js
ry authored
24 #include <node_buffer.h>
25
0afed52 @ry initial blobs
ry authored
26 #include <v8.h>
469e264 @ry More bindings, beginning tcp server code in js
ry authored
27
e0f47be @piscisaureus Clean up the way windows headers are included
piscisaureus authored
28 #include <assert.h>
29 #include <stdlib.h> // malloc, free
8e5b91c @ry Revert "Check for strings.h"
ry authored
30 #include <string.h> // memcpy
b72ffc0 @ry Add buffer.copy
ry authored
31
6d1af51 @piscisaureus Fix header files for node_buffer.cc
piscisaureus authored
32 #ifdef __MINGW32__
a7bdaab @bnoordhuis Include "platform.h", not <platform.h> - conflicts with system headers
bnoordhuis authored
33 # include "platform.h"
e0f47be @piscisaureus Clean up the way windows headers are included
piscisaureus authored
34 #endif
35
36 #ifdef __POSIX__
4a2cb07 @piscisaureus Fix whitespace errors introduced by porting efforts
piscisaureus authored
37 # include <arpa/inet.h> // htons, htonl
6d1af51 @piscisaureus Fix header files for node_buffer.cc
piscisaureus authored
38 #endif
7855316 @ry Add buffer.unpack
ry authored
39
0afed52 @ry initial blobs
ry authored
40
c1a0ade @ry Further net2 compatibilities
ry authored
41 #define MIN(a,b) ((a) < (b) ? (a) : (b))
42
0afed52 @ry initial blobs
ry authored
43 namespace node {
44
45 using namespace v8;
46
bf803f4 @ry Reimplment Buffers
ry authored
47 #define SLICE_ARGS(start_arg, end_arg) \
48 if (!start_arg->IsInt32() || !end_arg->IsInt32()) { \
49 return ThrowException(Exception::TypeError( \
50 String::New("Bad argument."))); \
51 } \
52 int32_t start = start_arg->Int32Value(); \
53 int32_t end = end_arg->Int32Value(); \
54 if (start < 0 || end < 0) { \
55 return ThrowException(Exception::TypeError( \
56 String::New("Bad argument."))); \
57 } \
58 if (!(start <= end)) { \
59 return ThrowException(Exception::Error( \
60 String::New("Must have start <= end"))); \
61 } \
62 if ((size_t)end > parent->length_) { \
63 return ThrowException(Exception::Error( \
64 String::New("end cannot be longer than parent.length"))); \
65 }
0afed52 @ry initial blobs
ry authored
66
67
bf803f4 @ry Reimplment Buffers
ry authored
68 static Persistent<String> length_symbol;
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
69 static Persistent<String> chars_written_sym;
0a53986 @felixge Support arrays and strings in buffer constructor
felixge authored
70 static Persistent<String> write_sym;
bf803f4 @ry Reimplment Buffers
ry authored
71 Persistent<FunctionTemplate> Buffer::constructor_template;
0afed52 @ry initial blobs
ry authored
72
73
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
74 static inline size_t base64_decoded_size(const char *src, size_t size) {
75 const char *const end = src + size;
76 const int remainder = size % 4;
77
78 size = (size / 4) * 3;
79 if (remainder) {
80 if (size == 0 && remainder == 1) {
81 // special case: 1-byte input cannot be decoded
82 size = 0;
83 } else {
84 // non-padded input, add 1 or 2 extra bytes
85 size += 1 + (remainder == 3);
86 }
87 }
88
89 // check for trailing padding (1 or 2 bytes)
90 if (size > 0) {
91 if (end[-1] == '=') size--;
92 if (end[-2] == '=') size--;
93 }
94
95 return size;
96 }
97
6135941 @ry Fix ByteLength hangup
ry authored
98
99 static size_t ByteLength (Handle<String> string, enum encoding enc) {
100 HandleScope scope;
101
102 if (enc == UTF8) {
103 return string->Utf8Length();
104 } else if (enc == BASE64) {
105 String::Utf8Value v(string);
106 return base64_decoded_size(*v, v.length());
9e101f2 UCS-2 support
Konstantin Käfer authored
107 } else if (enc == UCS2) {
108 return string->Length() * 2;
0aa1a8a @isaacs Closes GH-695 Add 'hex' encoding to Buffer
isaacs authored
109 } else if (enc == HEX) {
110 return string->Length() / 2;
6135941 @ry Fix ByteLength hangup
ry authored
111 } else {
112 return string->Length();
113 }
114 }
115
116
2320497 @ry Revert "Merge branch 'writev'"
ry authored
117 Handle<Object> Buffer::New(Handle<String> string) {
dcc4fff @ry Add C++ API for constructing fast buffer from string
ry authored
118 HandleScope scope;
119
120 // get Buffer from global scope.
121 Local<Object> global = v8::Context::GetCurrent()->Global();
122 Local<Value> bv = global->Get(String::NewSymbol("Buffer"));
123 assert(bv->IsFunction());
124 Local<Function> b = Local<Function>::Cast(bv);
125
2320497 @ry Revert "Merge branch 'writev'"
ry authored
126 Local<Value> argv[1] = { Local<Value>::New(string) };
127 Local<Object> instance = b->NewInstance(1, argv);
dcc4fff @ry Add C++ API for constructing fast buffer from string
ry authored
128
129 return scope.Close(instance);
130 }
131
132
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
133 Buffer* Buffer::New(size_t length) {
3768aaa @ry Create a public Buffer constructor for use in addons.
ry authored
134 HandleScope scope;
135
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
136 Local<Value> arg = Integer::NewFromUnsigned(length);
3768aaa @ry Create a public Buffer constructor for use in addons.
ry authored
137 Local<Object> b = constructor_template->GetFunction()->NewInstance(1, &arg);
8b33a1d @ry Guard failed buffer constructions.
ry authored
138 if (b.IsEmpty()) return NULL;
3768aaa @ry Create a public Buffer constructor for use in addons.
ry authored
139
140 return ObjectWrap::Unwrap<Buffer>(b);
141 }
142
0afed52 @ry initial blobs
ry authored
143
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
144 Buffer* Buffer::New(char* data, size_t length) {
0cf03ab @ry Add char* constructor for Buffer
ry authored
145 HandleScope scope;
146
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
147 Local<Value> arg = Integer::NewFromUnsigned(0);
0cf03ab @ry Add char* constructor for Buffer
ry authored
148 Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
149
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
150 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
151 buffer->Replace(data, length, NULL, NULL);
0cf03ab @ry Add char* constructor for Buffer
ry authored
152
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
153 return buffer;
154 }
155
156
157 Buffer* Buffer::New(char *data, size_t length,
158 free_callback callback, void *hint) {
159 HandleScope scope;
160
161 Local<Value> arg = Integer::NewFromUnsigned(0);
162 Local<Object> obj = constructor_template->GetFunction()->NewInstance(1, &arg);
163
164 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(obj);
165 buffer->Replace(data, length, callback, hint);
9d248f6 @ry Fix return in Buffer::New
ry authored
166
167 return buffer;
0cf03ab @ry Add char* constructor for Buffer
ry authored
168 }
169
170
bf803f4 @ry Reimplment Buffers
ry authored
171 Handle<Value> Buffer::New(const Arguments &args) {
f86ad16 @ry Safe Constructor: Buffer
ry authored
172 if (!args.IsConstructCall()) {
55c65cc @bnoordhuis Safe constructor for ObjectWrapped classes
bnoordhuis authored
173 return FromConstructorTemplate(constructor_template, args);
f86ad16 @ry Safe Constructor: Buffer
ry authored
174 }
175
55c65cc @bnoordhuis Safe constructor for ObjectWrapped classes
bnoordhuis authored
176 HandleScope scope;
177
bf803f4 @ry Reimplment Buffers
ry authored
178 Buffer *buffer;
179 if (args[0]->IsInt32()) {
180 // var buffer = new Buffer(1024);
181 size_t length = args[0]->Uint32Value();
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
182 buffer = new Buffer(args.This(), length);
0afed52 @ry initial blobs
ry authored
183 } else {
bf803f4 @ry Reimplment Buffers
ry authored
184 return ThrowException(Exception::TypeError(String::New("Bad argument")));
0afed52 @ry initial blobs
ry authored
185 }
bf803f4 @ry Reimplment Buffers
ry authored
186 return args.This();
187 }
0afed52 @ry initial blobs
ry authored
188
189
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
190 Buffer::Buffer(Handle<Object> wrapper, size_t length) : ObjectWrap() {
191 Wrap(wrapper);
192
193 length_ = 0;
194 callback_ = NULL;
85487c8 @ry Blob struct should not contain actual data
ry authored
195
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
196 Replace(NULL, length, NULL, NULL);
bf803f4 @ry Reimplment Buffers
ry authored
197 }
0afed52 @ry initial blobs
ry authored
198
199
bf803f4 @ry Reimplment Buffers
ry authored
200 Buffer::~Buffer() {
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
201 Replace(NULL, 0, NULL, NULL);
202 }
203
204
205 void Buffer::Replace(char *data, size_t length,
206 free_callback callback, void *hint) {
207 HandleScope scope;
208
209 if (callback_) {
210 callback_(data_, callback_hint_);
211 } else if (length_) {
6285fac @thughes Allocations with new[] must be freed with delete[].
thughes authored
212 delete [] data_;
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
213 V8::AdjustAmountOfExternalAllocatedMemory(-(sizeof(Buffer) + length_));
214 }
215
216 length_ = length;
217 callback_ = callback;
218 callback_hint_ = hint;
219
220 if (callback_) {
221 data_ = data;
222 } else if (length_) {
223 data_ = new char[length_];
224 if (data)
225 memcpy(data_, data, length_);
226 V8::AdjustAmountOfExternalAllocatedMemory(sizeof(Buffer) + length_);
227 } else {
228 data_ = NULL;
229 }
230
231 handle_->SetIndexedPropertiesToExternalArrayData(data_,
232 kExternalUnsignedByteArray,
233 length_);
234 handle_->Set(length_symbol, Integer::NewFromUnsigned(length_));
bf803f4 @ry Reimplment Buffers
ry authored
235 }
0afed52 @ry initial blobs
ry authored
236
237
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
238 Handle<Value> Buffer::BinarySlice(const Arguments &args) {
239 HandleScope scope;
240 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
241 SLICE_ARGS(args[0], args[1])
242
b5359e4 @ry Warnings for new C++ buffer API
ry authored
243 char *data = parent->data_ + start;
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
244 //Local<String> string = String::New(data, end - start);
245
246 Local<Value> b = Encode(data, end - start, BINARY);
247
248 return scope.Close(b);
249 }
250
251
bf803f4 @ry Reimplment Buffers
ry authored
252 Handle<Value> Buffer::AsciiSlice(const Arguments &args) {
0afed52 @ry initial blobs
ry authored
253 HandleScope scope;
bf803f4 @ry Reimplment Buffers
ry authored
254 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
0afed52 @ry initial blobs
ry authored
255 SLICE_ARGS(args[0], args[1])
3d10852 @ry Disable AsciiSliceExt
ry authored
256
b5359e4 @ry Warnings for new C++ buffer API
ry authored
257 char* data = parent->data_ + start;
0474ce6 @ry Revert "buffer.toString() shouldn't include null values"
ry authored
258 Local<String> string = String::New(data, end - start);
3d10852 @ry Disable AsciiSliceExt
ry authored
259
0afed52 @ry initial blobs
ry authored
260 return scope.Close(string);
261 }
262
263
bf803f4 @ry Reimplment Buffers
ry authored
264 Handle<Value> Buffer::Utf8Slice(const Arguments &args) {
265 HandleScope scope;
266 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
0afed52 @ry initial blobs
ry authored
267 SLICE_ARGS(args[0], args[1])
0474ce6 @ry Revert "buffer.toString() shouldn't include null values"
ry authored
268 char *data = parent->data_ + start;
269 Local<String> string = String::New(data, end - start);
0afed52 @ry initial blobs
ry authored
270 return scope.Close(string);
271 }
272
9e101f2 UCS-2 support
Konstantin Käfer authored
273 Handle<Value> Buffer::Ucs2Slice(const Arguments &args) {
274 HandleScope scope;
275 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
276 SLICE_ARGS(args[0], args[1])
277 uint16_t *data = (uint16_t*)(parent->data_ + start);
278 Local<String> string = String::New(data, (end - start) / 2);
279 return scope.Close(string);
280 }
281
eeaf1ef @d0k Constify read-only global data
d0k authored
282 static const char *base64_table = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
283 "abcdefghijklmnopqrstuvwxyz"
284 "0123456789+/";
285 static const int unbase64_table[] =
cf1db4f @ry base64 decode should handle whitespace
ry authored
286 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-1
2c1ca40 @ry Implement buffer.write for base64
ry authored
287 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
cf1db4f @ry base64 decode should handle whitespace
ry authored
288 ,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,-1,-1,-1,63
2c1ca40 @ry Implement buffer.write for base64
ry authored
289 ,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-1,-1,-1
290 ,-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14
291 ,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1
292 ,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40
293 ,41,42,43,44,45,46,47,48,49,50,51,-1,-1,-1,-1,-1
c735b46 @xk unbase64 skips over *any* illegal chars
xk authored
294 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
295 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
296 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
297 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
298 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
299 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
300 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
301 ,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
2c1ca40 @ry Implement buffer.write for base64
ry authored
302 };
c735b46 @xk unbase64 skips over *any* illegal chars
xk authored
303 #define unbase64(x) unbase64_table[(uint8_t)(x)]
528015e @ry Implement buffer.toString('base64')
ry authored
304
305
306 Handle<Value> Buffer::Base64Slice(const Arguments &args) {
307 HandleScope scope;
308 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
309 SLICE_ARGS(args[0], args[1])
310
311 int n = end - start;
312 int out_len = (n + 2 - ((n + 2) % 3)) / 3 * 4;
313 char *out = new char[out_len];
314
7db5c8a @ry Fix toString('base64') bug
ry authored
315 uint8_t bitbuf[3];
528015e @ry Implement buffer.toString('base64')
ry authored
316 int i = start; // data() index
317 int j = 0; // out index
318 char c;
319 bool b1_oob, b2_oob;
320
321 while (i < end) {
b5359e4 @ry Warnings for new C++ buffer API
ry authored
322 bitbuf[0] = parent->data_[i++];
528015e @ry Implement buffer.toString('base64')
ry authored
323
324 if (i < end) {
b5359e4 @ry Warnings for new C++ buffer API
ry authored
325 bitbuf[1] = parent->data_[i];
528015e @ry Implement buffer.toString('base64')
ry authored
326 b1_oob = false;
327 } else {
328 bitbuf[1] = 0;
329 b1_oob = true;
330 }
331 i++;
332
333 if (i < end) {
b5359e4 @ry Warnings for new C++ buffer API
ry authored
334 bitbuf[2] = parent->data_[i];
528015e @ry Implement buffer.toString('base64')
ry authored
335 b2_oob = false;
336 } else {
337 bitbuf[2] = 0;
338 b2_oob = true;
339 }
340 i++;
341
342
343 c = bitbuf[0] >> 2;
344 assert(c < 64);
fe74283 @ry Fix a few compiler warnings...
ry authored
345 out[j++] = base64_table[(int)c];
528015e @ry Implement buffer.toString('base64')
ry authored
346 assert(j < out_len);
347
348 c = ((bitbuf[0] & 0x03) << 4) | (bitbuf[1] >> 4);
349 assert(c < 64);
fe74283 @ry Fix a few compiler warnings...
ry authored
350 out[j++] = base64_table[(int)c];
528015e @ry Implement buffer.toString('base64')
ry authored
351 assert(j < out_len);
352
353 if (b1_oob) {
354 out[j++] = '=';
355 } else {
356 c = ((bitbuf[1] & 0x0F) << 2) | (bitbuf[2] >> 6);
357 assert(c < 64);
fe74283 @ry Fix a few compiler warnings...
ry authored
358 out[j++] = base64_table[(int)c];
528015e @ry Implement buffer.toString('base64')
ry authored
359 }
360 assert(j < out_len);
361
362 if (b2_oob) {
363 out[j++] = '=';
364 } else {
365 c = bitbuf[2] & 0x3F;
366 assert(c < 64);
fe74283 @ry Fix a few compiler warnings...
ry authored
367 out[j++] = base64_table[(int)c];
528015e @ry Implement buffer.toString('base64')
ry authored
368 }
369 assert(j <= out_len);
370 }
371
372 Local<String> string = String::New(out, out_len);
373 delete [] out;
374 return scope.Close(string);
375 }
376
0afed52 @ry initial blobs
ry authored
377
5e1b7ca Add Buffer::fill method to do memset
Konstantin Käfer authored
378 // buffer.fill(value, start, end);
379 Handle<Value> Buffer::Fill(const Arguments &args) {
380 HandleScope scope;
381
382 if (!args[0]->IsInt32()) {
383 return ThrowException(Exception::Error(String::New(
384 "value is not a number")));
385 }
386 int value = (char)args[0]->Int32Value();
387
388 Buffer *parent = ObjectWrap::Unwrap<Buffer>(args.This());
389 SLICE_ARGS(args[1], args[2])
390
391 memset( (void*)(parent->data_ + start),
392 value,
393 end - start);
394
395 return Undefined();
396 }
397
398
b72ffc0 @ry Add buffer.copy
ry authored
399 // var bytesCopied = buffer.copy(target, targetStart, sourceStart, sourceEnd);
400 Handle<Value> Buffer::Copy(const Arguments &args) {
401 HandleScope scope;
402
403 Buffer *source = ObjectWrap::Unwrap<Buffer>(args.This());
404
405 if (!Buffer::HasInstance(args[0])) {
406 return ThrowException(Exception::TypeError(String::New(
407 "First arg should be a Buffer")));
408 }
409
b3e60c7 @stephank Generalize Buffer::Copy to work with all unsigned byte external data.
stephank authored
410 Local<Object> target = args[0]->ToObject();
411 char *target_data = Buffer::Data(target);
412 ssize_t target_length = Buffer::Length(target);
b72ffc0 @ry Add buffer.copy
ry authored
413
414 ssize_t target_start = args[1]->Int32Value();
415 ssize_t source_start = args[2]->Int32Value();
416 ssize_t source_end = args[3]->IsInt32() ? args[3]->Int32Value()
b5359e4 @ry Warnings for new C++ buffer API
ry authored
417 : source->length_;
b72ffc0 @ry Add buffer.copy
ry authored
418
419 if (source_end < source_start) {
420 return ThrowException(Exception::Error(String::New(
421 "sourceEnd < sourceStart")));
422 }
423
e7c4f8c @pgriess Buffer.copy() should liberally allow empty copies.
pgriess authored
424 // Copy 0 bytes; we're done
425 if (source_end == source_start) {
426 return scope.Close(Integer::New(0));
427 }
428
b3e60c7 @stephank Generalize Buffer::Copy to work with all unsigned byte external data.
stephank authored
429 if (target_start < 0 || target_start >= target_length) {
b72ffc0 @ry Add buffer.copy
ry authored
430 return ThrowException(Exception::Error(String::New(
431 "targetStart out of bounds")));
432 }
433
b5359e4 @ry Warnings for new C++ buffer API
ry authored
434 if (source_start < 0 || source_start >= source->length_) {
b72ffc0 @ry Add buffer.copy
ry authored
435 return ThrowException(Exception::Error(String::New(
436 "sourceStart out of bounds")));
437 }
438
b5359e4 @ry Warnings for new C++ buffer API
ry authored
439 if (source_end < 0 || source_end > source->length_) {
b72ffc0 @ry Add buffer.copy
ry authored
440 return ThrowException(Exception::Error(String::New(
441 "sourceEnd out of bounds")));
442 }
443
d5bdda7 @ry fast buffer bounds checking in copy()
ry authored
444 ssize_t to_copy = MIN(MIN(source_end - source_start,
b3e60c7 @stephank Generalize Buffer::Copy to work with all unsigned byte external data.
stephank authored
445 target_length - target_start),
b5359e4 @ry Warnings for new C++ buffer API
ry authored
446 source->length_ - source_start);
fcc3812 @brapse Check buffer length using string length
brapse authored
447
b72ffc0 @ry Add buffer.copy
ry authored
448
5bc4efe @ry Remove blobs, simplify SlowBuffer
ry authored
449 // need to use slightly slower memmove is the ranges might overlap
b3e60c7 @stephank Generalize Buffer::Copy to work with all unsigned byte external data.
stephank authored
450 memmove((void *)(target_data + target_start),
b5359e4 @ry Warnings for new C++ buffer API
ry authored
451 (const void*)(source->data_ + source_start),
5bc4efe @ry Remove blobs, simplify SlowBuffer
ry authored
452 to_copy);
b72ffc0 @ry Add buffer.copy
ry authored
453
454 return scope.Close(Integer::New(to_copy));
455 }
456
457
7b772f3 @ry More fast buffer work
ry authored
458 // var charsWritten = buffer.utf8Write(string, offset, [maxLength]);
bf803f4 @ry Reimplment Buffers
ry authored
459 Handle<Value> Buffer::Utf8Write(const Arguments &args) {
bddd6e9 @ry Implement stream.send()
ry authored
460 HandleScope scope;
bf803f4 @ry Reimplment Buffers
ry authored
461 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
bddd6e9 @ry Implement stream.send()
ry authored
462
463 if (!args[0]->IsString()) {
464 return ThrowException(Exception::TypeError(String::New(
465 "Argument must be a string")));
466 }
467
468 Local<String> s = args[0]->ToString();
469
7b772f3 @ry More fast buffer work
ry authored
470 size_t offset = args[1]->Uint32Value();
bddd6e9 @ry Implement stream.send()
ry authored
471
5208abe Fix Buffer drops last null character in UTF-8
koichik authored
472 int length = s->Length();
473
474 if (length == 0) {
475 constructor_template->GetFunction()->Set(chars_written_sym,
476 Integer::New(0));
477 return scope.Close(Integer::New(0));
478 }
479
480 if (length > 0 && offset >= buffer->length_) {
bddd6e9 @ry Implement stream.send()
ry authored
481 return ThrowException(Exception::TypeError(String::New(
482 "Offset is out of bounds")));
483 }
484
efc7237 @ry Fix big string bug
ry authored
485 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
486 : args[2]->Uint32Value();
7b772f3 @ry More fast buffer work
ry authored
487 max_length = MIN(buffer->length_ - offset, max_length);
488
b5359e4 @ry Warnings for new C++ buffer API
ry authored
489 char* p = buffer->data_ + offset;
bddd6e9 @ry Implement stream.send()
ry authored
490
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
491 int char_written;
492
1f947f7 @ry remove unnecessary casts
ry authored
493 int written = s->WriteUtf8(p,
7b772f3 @ry More fast buffer work
ry authored
494 max_length,
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
495 &char_written,
41ef171 @ry Upgrade V8 to 2.2.3.1
ry authored
496 String::HINT_MANY_WRITES_EXPECTED);
c1a0ade @ry Further net2 compatibilities
ry authored
497
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
498 constructor_template->GetFunction()->Set(chars_written_sym,
499 Integer::New(char_written));
500
5208abe Fix Buffer drops last null character in UTF-8
koichik authored
501 if (written > 0 && p[written-1] == '\0' && char_written == length) {
502 uint16_t last_char;
7d38a3b @ry Fix build - due to V8 API change
ry authored
503 s->Write(&last_char, length - 1, 1, String::NO_OPTIONS);
5208abe Fix Buffer drops last null character in UTF-8
koichik authored
504 if (last_char != 0 || written > s->Utf8Length()) {
505 written--;
506 }
507 }
53dd9fe @ry Fix bug in buffer.utf8Write() which included \u0000
ry authored
508
bddd6e9 @ry Implement stream.send()
ry authored
509 return scope.Close(Integer::New(written));
510 }
511
512
9e101f2 UCS-2 support
Konstantin Käfer authored
513 // var charsWritten = buffer.ucs2Write(string, offset, [maxLength]);
514 Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
515 HandleScope scope;
516 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
517
518 if (!args[0]->IsString()) {
519 return ThrowException(Exception::TypeError(String::New(
520 "Argument must be a string")));
521 }
522
523 Local<String> s = args[0]->ToString();
524
525 size_t offset = args[1]->Uint32Value();
526
527 if (s->Length() > 0 && offset >= buffer->length_) {
528 return ThrowException(Exception::TypeError(String::New(
529 "Offset is out of bounds")));
530 }
531
532 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
533 : args[2]->Uint32Value();
9533e87 Fix Buffer.write() with UCS-2 should not be write partial char
koichik authored
534 max_length = MIN(buffer->length_ - offset, max_length) / 2;
9e101f2 UCS-2 support
Konstantin Käfer authored
535
536 uint16_t* p = (uint16_t*)(buffer->data_ + offset);
537
538 int written = s->Write(p,
539 0,
540 max_length,
541 String::HINT_MANY_WRITES_EXPECTED);
9533e87 Fix Buffer.write() with UCS-2 should not be write partial char
koichik authored
542
543 constructor_template->GetFunction()->Set(chars_written_sym,
544 Integer::New(written));
545
9e101f2 UCS-2 support
Konstantin Käfer authored
546 return scope.Close(Integer::New(written * 2));
547 }
548
549
bf803f4 @ry Reimplment Buffers
ry authored
550 // var charsWritten = buffer.asciiWrite(string, offset);
551 Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
bddd6e9 @ry Implement stream.send()
ry authored
552 HandleScope scope;
553
bf803f4 @ry Reimplment Buffers
ry authored
554 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
bddd6e9 @ry Implement stream.send()
ry authored
555
556 if (!args[0]->IsString()) {
557 return ThrowException(Exception::TypeError(String::New(
558 "Argument must be a string")));
559 }
560
561 Local<String> s = args[0]->ToString();
562
563 size_t offset = args[1]->Int32Value();
564
b64a521 @pgriess Buffer('') should create a 0-length buffer
pgriess authored
565 if (s->Length() > 0 && offset >= buffer->length_) {
bddd6e9 @ry Implement stream.send()
ry authored
566 return ThrowException(Exception::TypeError(String::New(
567 "Offset is out of bounds")));
568 }
569
efc7237 @ry Fix big string bug
ry authored
570 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
571 : args[2]->Uint32Value();
7b772f3 @ry More fast buffer work
ry authored
572 max_length = MIN(s->Length(), MIN(buffer->length_ - offset, max_length));
bddd6e9 @ry Implement stream.send()
ry authored
573
b5359e4 @ry Warnings for new C++ buffer API
ry authored
574 char *p = buffer->data_ + offset;
bddd6e9 @ry Implement stream.send()
ry authored
575
1f947f7 @ry remove unnecessary casts
ry authored
576 int written = s->WriteAscii(p,
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
577 0,
7b772f3 @ry More fast buffer work
ry authored
578 max_length,
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
579 String::HINT_MANY_WRITES_EXPECTED);
bddd6e9 @ry Implement stream.send()
ry authored
580 return scope.Close(Integer::New(written));
581 }
582
cf1db4f @ry base64 decode should handle whitespace
ry authored
583
7b772f3 @ry More fast buffer work
ry authored
584 // var bytesWritten = buffer.base64Write(string, offset, [maxLength]);
2c1ca40 @ry Implement buffer.write for base64
ry authored
585 Handle<Value> Buffer::Base64Write(const Arguments &args) {
586 HandleScope scope;
587
cf1db4f @ry base64 decode should handle whitespace
ry authored
588 assert(unbase64('/') == 63);
589 assert(unbase64('+') == 62);
590 assert(unbase64('T') == 19);
591 assert(unbase64('Z') == 25);
592 assert(unbase64('t') == 45);
593 assert(unbase64('z') == 51);
594
595 assert(unbase64(' ') == -2);
596 assert(unbase64('\n') == -2);
597 assert(unbase64('\r') == -2);
2c1ca40 @ry Implement buffer.write for base64
ry authored
598
599 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
600
601 if (!args[0]->IsString()) {
602 return ThrowException(Exception::TypeError(String::New(
603 "Argument must be a string")));
604 }
605
606 String::AsciiValue s(args[0]->ToString());
607 size_t offset = args[1]->Int32Value();
608
95638c9 @bnoordhuis Buffer: adjust buffer size so the base64-decoded input fits snugly.
bnoordhuis authored
609 // handle zero-length buffers graciously
610 if (offset == 0 && buffer->length_ == 0) {
611 return scope.Close(Integer::New(0));
612 }
613
2c1ca40 @ry Implement buffer.write for base64
ry authored
614 if (offset >= buffer->length_) {
615 return ThrowException(Exception::TypeError(String::New(
616 "Offset is out of bounds")));
617 }
618
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
619 const size_t size = base64_decoded_size(*s, s.length());
620 if (size > buffer->length_ - offset) {
621 // throw exception, don't silently truncate
622 return ThrowException(Exception::TypeError(String::New(
623 "Buffer too small")));
624 }
2c1ca40 @ry Implement buffer.write for base64
ry authored
625
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
626 char a, b, c, d;
cf1db4f @ry base64 decode should handle whitespace
ry authored
627 char* start = buffer->data_ + offset;
628 char* dst = start;
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
629 const char *src = *s;
630 const char *const srcEnd = src + s.length();
631
632 while (src < srcEnd) {
cf1db4f @ry base64 decode should handle whitespace
ry authored
633 int remaining = srcEnd - src;
634
635 while (unbase64(*src) < 0 && src < srcEnd) {
636 src++;
637 remaining--;
638 }
c38dd24 @ry Fix style
ry authored
639 if (remaining == 0 || *src == '=') break;
cf1db4f @ry base64 decode should handle whitespace
ry authored
640 a = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
641
cf1db4f @ry base64 decode should handle whitespace
ry authored
642 while (unbase64(*src) < 0 && src < srcEnd) {
643 src++;
644 remaining--;
645 }
646 if (remaining <= 1 || *src == '=') break;
647 b = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
648 *dst++ = (a << 2) | ((b & 0x30) >> 4);
649
cf1db4f @ry base64 decode should handle whitespace
ry authored
650 while (unbase64(*src) < 0 && src < srcEnd) {
651 src++;
652 remaining--;
653 }
654 if (remaining <= 2 || *src == '=') break;
655 c = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
656 *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
657
cf1db4f @ry base64 decode should handle whitespace
ry authored
658 while (unbase64(*src) < 0 && src < srcEnd) {
659 src++;
660 remaining--;
661 }
662 if (remaining <= 3 || *src == '=') break;
663 d = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
664 *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
2c1ca40 @ry Implement buffer.write for base64
ry authored
665 }
666
cf1db4f @ry base64 decode should handle whitespace
ry authored
667 return scope.Close(Integer::New(dst - start));
2c1ca40 @ry Implement buffer.write for base64
ry authored
668 }
669
670
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
671 Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
672 HandleScope scope;
673
674 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
675
676 if (!args[0]->IsString()) {
677 return ThrowException(Exception::TypeError(String::New(
678 "Argument must be a string")));
679 }
680
681 Local<String> s = args[0]->ToString();
682
683 size_t offset = args[1]->Int32Value();
684
b64a521 @pgriess Buffer('') should create a 0-length buffer
pgriess authored
685 if (s->Length() > 0 && offset >= buffer->length_) {
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
686 return ThrowException(Exception::TypeError(String::New(
687 "Offset is out of bounds")));
688 }
689
b5359e4 @ry Warnings for new C++ buffer API
ry authored
690 char *p = (char*)buffer->data_ + offset;
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
691
692 size_t towrite = MIN((unsigned long) s->Length(), buffer->length_ - offset);
693
694 int written = DecodeWrite(p, towrite, s, BINARY);
695 return scope.Close(Integer::New(written));
696 }
697
698
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
699 // var nbytes = Buffer.byteLength("string", "utf8")
700 Handle<Value> Buffer::ByteLength(const Arguments &args) {
bddd6e9 @ry Implement stream.send()
ry authored
701 HandleScope scope;
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
702
bddd6e9 @ry Implement stream.send()
ry authored
703 if (!args[0]->IsString()) {
704 return ThrowException(Exception::TypeError(String::New(
705 "Argument must be a string")));
706 }
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
707
bddd6e9 @ry Implement stream.send()
ry authored
708 Local<String> s = args[0]->ToString();
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
709 enum encoding e = ParseEncoding(args[1], UTF8);
8c85340 @bmizerany fix whitespace errors
bmizerany authored
710
6135941 @ry Fix ByteLength hangup
ry authored
711 return scope.Close(Integer::New(node::ByteLength(s, e)));
bddd6e9 @ry Implement stream.send()
ry authored
712 }
713
714
488aff0 @ry Improve appendix markdown
ry authored
715 Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
716 HandleScope scope;
717
5e409c2 @ry makeFastBuffer should not segfault but rather throw on non-buffer
ry authored
718 if (!Buffer::HasInstance(args[0])) {
719 return ThrowException(Exception::TypeError(String::New(
720 "First argument must be a Buffer")));
721 }
722
488aff0 @ry Improve appendix markdown
ry authored
723 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
724 Local<Object> fast_buffer = args[1]->ToObject();;
725 uint32_t offset = args[2]->Uint32Value();
726 uint32_t length = args[3]->Uint32Value();
727
d5e9661 @stephank Simplify things by using `*ArrayData` everywhere.
stephank authored
728 fast_buffer->SetIndexedPropertiesToExternalArrayData(buffer->data_ + offset,
729 kExternalUnsignedByteArray,
730 length);
488aff0 @ry Improve appendix markdown
ry authored
731
732 return Undefined();
733 }
734
735
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
736 bool Buffer::HasInstance(v8::Handle<v8::Value> val) {
737 if (!val->IsObject()) return false;
738 v8::Local<v8::Object> obj = val->ToObject();
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
739
740 if (obj->GetIndexedPropertiesExternalArrayDataType() == kExternalUnsignedByteArray)
741 return true;
742
743 // Also check for SlowBuffers that are empty.
744 if (constructor_template->HasInstance(obj))
745 return true;
746
747 return false;
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
748 }
749
488aff0 @ry Improve appendix markdown
ry authored
750
bf803f4 @ry Reimplment Buffers
ry authored
751 void Buffer::Initialize(Handle<Object> target) {
0afed52 @ry initial blobs
ry authored
752 HandleScope scope;
753
754 length_symbol = Persistent<String>::New(String::NewSymbol("length"));
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
755 chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
0afed52 @ry initial blobs
ry authored
756
bf803f4 @ry Reimplment Buffers
ry authored
757 Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
0afed52 @ry initial blobs
ry authored
758 constructor_template = Persistent<FunctionTemplate>::New(t);
759 constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
b8bfbda @ry Rename SlowBuffer in binding
ry authored
760 constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
0afed52 @ry initial blobs
ry authored
761
762 // copy free
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
763 NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
bf803f4 @ry Reimplment Buffers
ry authored
764 NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
528015e @ry Implement buffer.toString('base64')
ry authored
765 NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
9e101f2 UCS-2 support
Konstantin Käfer authored
766 NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
0afed52 @ry initial blobs
ry authored
767 // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
bf803f4 @ry Reimplment Buffers
ry authored
768 // copy
769 NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
0afed52 @ry initial blobs
ry authored
770
bf803f4 @ry Reimplment Buffers
ry authored
771 NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
772 NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
773 NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
2c1ca40 @ry Implement buffer.write for base64
ry authored
774 NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
9e101f2 UCS-2 support
Konstantin Käfer authored
775 NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
5e1b7ca Add Buffer::fill method to do memset
Konstantin Käfer authored
776 NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill);
b72ffc0 @ry Add buffer.copy
ry authored
777 NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
bddd6e9 @ry Implement stream.send()
ry authored
778
4f56d8a @ry Rename Buffer.utf8Length to Buffer.utf8ByteLength
ry authored
779 NODE_SET_METHOD(constructor_template->GetFunction(),
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
780 "byteLength",
781 Buffer::ByteLength);
488aff0 @ry Improve appendix markdown
ry authored
782 NODE_SET_METHOD(constructor_template->GetFunction(),
783 "makeFastBuffer",
784 Buffer::MakeFastBuffer);
bddd6e9 @ry Implement stream.send()
ry authored
785
b8bfbda @ry Rename SlowBuffer in binding
ry authored
786 target->Set(String::NewSymbol("SlowBuffer"), constructor_template->GetFunction());
0afed52 @ry initial blobs
ry authored
787 }
788
bf803f4 @ry Reimplment Buffers
ry authored
789
0afed52 @ry initial blobs
ry authored
790 } // namespace node
82daa46 @pquerna Move Buffer to extension model.
pquerna authored
791
792 NODE_MODULE(node_buffer, node::Buffer::Initialize);
Something went wrong with that request. Please try again.