Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 801 lines (603 sloc) 24.132 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,
6a72e52 buffer: use NO_NULL_TERMINATION flag
koichik authored
496 (String::HINT_MANY_WRITES_EXPECTED |
497 String::NO_NULL_TERMINATION));
c1a0ade @ry Further net2 compatibilities
ry authored
498
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
499 constructor_template->GetFunction()->Set(chars_written_sym,
500 Integer::New(char_written));
501
bddd6e9 @ry Implement stream.send()
ry authored
502 return scope.Close(Integer::New(written));
503 }
504
505
9e101f2 UCS-2 support
Konstantin Käfer authored
506 // var charsWritten = buffer.ucs2Write(string, offset, [maxLength]);
507 Handle<Value> Buffer::Ucs2Write(const Arguments &args) {
508 HandleScope scope;
509 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
510
511 if (!args[0]->IsString()) {
512 return ThrowException(Exception::TypeError(String::New(
513 "Argument must be a string")));
514 }
515
516 Local<String> s = args[0]->ToString();
517
518 size_t offset = args[1]->Uint32Value();
519
520 if (s->Length() > 0 && offset >= buffer->length_) {
521 return ThrowException(Exception::TypeError(String::New(
522 "Offset is out of bounds")));
523 }
524
525 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
526 : args[2]->Uint32Value();
9533e87 Fix Buffer.write() with UCS-2 should not be write partial char
koichik authored
527 max_length = MIN(buffer->length_ - offset, max_length) / 2;
9e101f2 UCS-2 support
Konstantin Käfer authored
528
529 uint16_t* p = (uint16_t*)(buffer->data_ + offset);
530
531 int written = s->Write(p,
532 0,
533 max_length,
6a72e52 buffer: use NO_NULL_TERMINATION flag
koichik authored
534 (String::HINT_MANY_WRITES_EXPECTED |
535 String::NO_NULL_TERMINATION));
9533e87 Fix Buffer.write() with UCS-2 should not be write partial char
koichik authored
536
537 constructor_template->GetFunction()->Set(chars_written_sym,
538 Integer::New(written));
539
9e101f2 UCS-2 support
Konstantin Käfer authored
540 return scope.Close(Integer::New(written * 2));
541 }
542
543
bf803f4 @ry Reimplment Buffers
ry authored
544 // var charsWritten = buffer.asciiWrite(string, offset);
545 Handle<Value> Buffer::AsciiWrite(const Arguments &args) {
bddd6e9 @ry Implement stream.send()
ry authored
546 HandleScope scope;
547
bf803f4 @ry Reimplment Buffers
ry authored
548 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
bddd6e9 @ry Implement stream.send()
ry authored
549
550 if (!args[0]->IsString()) {
551 return ThrowException(Exception::TypeError(String::New(
552 "Argument must be a string")));
553 }
554
555 Local<String> s = args[0]->ToString();
556
557 size_t offset = args[1]->Int32Value();
558
b64a521 @pgriess Buffer('') should create a 0-length buffer
pgriess authored
559 if (s->Length() > 0 && offset >= buffer->length_) {
bddd6e9 @ry Implement stream.send()
ry authored
560 return ThrowException(Exception::TypeError(String::New(
561 "Offset is out of bounds")));
562 }
563
efc7237 @ry Fix big string bug
ry authored
564 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
565 : args[2]->Uint32Value();
7b772f3 @ry More fast buffer work
ry authored
566 max_length = MIN(s->Length(), MIN(buffer->length_ - offset, max_length));
bddd6e9 @ry Implement stream.send()
ry authored
567
b5359e4 @ry Warnings for new C++ buffer API
ry authored
568 char *p = buffer->data_ + offset;
bddd6e9 @ry Implement stream.send()
ry authored
569
1f947f7 @ry remove unnecessary casts
ry authored
570 int written = s->WriteAscii(p,
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
571 0,
7b772f3 @ry More fast buffer work
ry authored
572 max_length,
6a72e52 buffer: use NO_NULL_TERMINATION flag
koichik authored
573 (String::HINT_MANY_WRITES_EXPECTED |
574 String::NO_NULL_TERMINATION));
3e853e6 buffer: write() should always set _charsWritten.
koichik authored
575
576 constructor_template->GetFunction()->Set(chars_written_sym,
577 Integer::New(written));
578
bddd6e9 @ry Implement stream.send()
ry authored
579 return scope.Close(Integer::New(written));
580 }
581
cf1db4f @ry base64 decode should handle whitespace
ry authored
582
7b772f3 @ry More fast buffer work
ry authored
583 // var bytesWritten = buffer.base64Write(string, offset, [maxLength]);
2c1ca40 @ry Implement buffer.write for base64
ry authored
584 Handle<Value> Buffer::Base64Write(const Arguments &args) {
585 HandleScope scope;
586
cf1db4f @ry base64 decode should handle whitespace
ry authored
587 assert(unbase64('/') == 63);
588 assert(unbase64('+') == 62);
589 assert(unbase64('T') == 19);
590 assert(unbase64('Z') == 25);
591 assert(unbase64('t') == 45);
592 assert(unbase64('z') == 51);
593
594 assert(unbase64(' ') == -2);
595 assert(unbase64('\n') == -2);
596 assert(unbase64('\r') == -2);
2c1ca40 @ry Implement buffer.write for base64
ry authored
597
598 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
599
600 if (!args[0]->IsString()) {
601 return ThrowException(Exception::TypeError(String::New(
602 "Argument must be a string")));
603 }
604
605 String::AsciiValue s(args[0]->ToString());
606 size_t offset = args[1]->Int32Value();
607
95638c9 @bnoordhuis Buffer: adjust buffer size so the base64-decoded input fits snugly.
bnoordhuis authored
608 // handle zero-length buffers graciously
609 if (offset == 0 && buffer->length_ == 0) {
610 return scope.Close(Integer::New(0));
611 }
612
2c1ca40 @ry Implement buffer.write for base64
ry authored
613 if (offset >= buffer->length_) {
614 return ThrowException(Exception::TypeError(String::New(
615 "Offset is out of bounds")));
616 }
617
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
618 const size_t size = base64_decoded_size(*s, s.length());
619 if (size > buffer->length_ - offset) {
620 // throw exception, don't silently truncate
621 return ThrowException(Exception::TypeError(String::New(
622 "Buffer too small")));
623 }
2c1ca40 @ry Implement buffer.write for base64
ry authored
624
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
625 char a, b, c, d;
cf1db4f @ry base64 decode should handle whitespace
ry authored
626 char* start = buffer->data_ + offset;
627 char* dst = start;
f72ac17 @bnoordhuis Buffer: graciously handle padding in base64-encoded input.
bnoordhuis authored
628 const char *src = *s;
629 const char *const srcEnd = src + s.length();
630
631 while (src < srcEnd) {
cf1db4f @ry base64 decode should handle whitespace
ry authored
632 int remaining = srcEnd - src;
633
634 while (unbase64(*src) < 0 && src < srcEnd) {
635 src++;
636 remaining--;
637 }
c38dd24 @ry Fix style
ry authored
638 if (remaining == 0 || *src == '=') break;
cf1db4f @ry base64 decode should handle whitespace
ry authored
639 a = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
640
cf1db4f @ry base64 decode should handle whitespace
ry authored
641 while (unbase64(*src) < 0 && src < srcEnd) {
642 src++;
643 remaining--;
644 }
645 if (remaining <= 1 || *src == '=') break;
646 b = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
647 *dst++ = (a << 2) | ((b & 0x30) >> 4);
648
cf1db4f @ry base64 decode should handle whitespace
ry authored
649 while (unbase64(*src) < 0 && src < srcEnd) {
650 src++;
651 remaining--;
652 }
653 if (remaining <= 2 || *src == '=') break;
654 c = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
655 *dst++ = ((b & 0x0F) << 4) | ((c & 0x3C) >> 2);
656
cf1db4f @ry base64 decode should handle whitespace
ry authored
657 while (unbase64(*src) < 0 && src < srcEnd) {
658 src++;
659 remaining--;
660 }
661 if (remaining <= 3 || *src == '=') break;
662 d = unbase64(*src++);
c38dd24 @ry Fix style
ry authored
663 *dst++ = ((c & 0x03) << 6) | (d & 0x3F);
2c1ca40 @ry Implement buffer.write for base64
ry authored
664 }
665
3e853e6 buffer: write() should always set _charsWritten.
koichik authored
666 constructor_template->GetFunction()->Set(chars_written_sym,
667 Integer::New(s.length()));
668
cf1db4f @ry base64 decode should handle whitespace
ry authored
669 return scope.Close(Integer::New(dst - start));
2c1ca40 @ry Implement buffer.write for base64
ry authored
670 }
671
672
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
673 Handle<Value> Buffer::BinaryWrite(const Arguments &args) {
674 HandleScope scope;
675
676 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args.This());
677
678 if (!args[0]->IsString()) {
679 return ThrowException(Exception::TypeError(String::New(
680 "Argument must be a string")));
681 }
682
683 Local<String> s = args[0]->ToString();
684
685 size_t offset = args[1]->Int32Value();
686
b64a521 @pgriess Buffer('') should create a 0-length buffer
pgriess authored
687 if (s->Length() > 0 && offset >= buffer->length_) {
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
688 return ThrowException(Exception::TypeError(String::New(
689 "Offset is out of bounds")));
690 }
691
b5359e4 @ry Warnings for new C++ buffer API
ry authored
692 char *p = (char*)buffer->data_ + offset;
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
693
96ede8c buffer: Avoid overrun with 'binary' encoding.
koichik authored
694 size_t max_length = args[2]->IsUndefined() ? buffer->length_ - offset
695 : args[2]->Uint32Value();
696 max_length = MIN(s->Length(), MIN(buffer->length_ - offset, max_length));
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
697
96ede8c buffer: Avoid overrun with 'binary' encoding.
koichik authored
698 int written = DecodeWrite(p, max_length, s, BINARY);
3e853e6 buffer: write() should always set _charsWritten.
koichik authored
699
700 constructor_template->GetFunction()->Set(chars_written_sym,
701 Integer::New(written));
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
702
703 return scope.Close(Integer::New(written));
704 }
705
706
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
707 // var nbytes = Buffer.byteLength("string", "utf8")
708 Handle<Value> Buffer::ByteLength(const Arguments &args) {
bddd6e9 @ry Implement stream.send()
ry authored
709 HandleScope scope;
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
710
bddd6e9 @ry Implement stream.send()
ry authored
711 if (!args[0]->IsString()) {
712 return ThrowException(Exception::TypeError(String::New(
713 "Argument must be a string")));
714 }
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
715
bddd6e9 @ry Implement stream.send()
ry authored
716 Local<String> s = args[0]->ToString();
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
717 enum encoding e = ParseEncoding(args[1], UTF8);
8c85340 @bmizerany fix whitespace errors
bmizerany authored
718
6135941 @ry Fix ByteLength hangup
ry authored
719 return scope.Close(Integer::New(node::ByteLength(s, e)));
bddd6e9 @ry Implement stream.send()
ry authored
720 }
721
722
488aff0 @ry Improve appendix markdown
ry authored
723 Handle<Value> Buffer::MakeFastBuffer(const Arguments &args) {
724 HandleScope scope;
725
5e409c2 @ry makeFastBuffer should not segfault but rather throw on non-buffer
ry authored
726 if (!Buffer::HasInstance(args[0])) {
727 return ThrowException(Exception::TypeError(String::New(
728 "First argument must be a Buffer")));
729 }
730
488aff0 @ry Improve appendix markdown
ry authored
731 Buffer *buffer = ObjectWrap::Unwrap<Buffer>(args[0]->ToObject());
732 Local<Object> fast_buffer = args[1]->ToObject();;
733 uint32_t offset = args[2]->Uint32Value();
734 uint32_t length = args[3]->Uint32Value();
735
d5e9661 @stephank Simplify things by using `*ArrayData` everywhere.
stephank authored
736 fast_buffer->SetIndexedPropertiesToExternalArrayData(buffer->data_ + offset,
737 kExternalUnsignedByteArray,
738 length);
488aff0 @ry Improve appendix markdown
ry authored
739
740 return Undefined();
741 }
742
743
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
744 bool Buffer::HasInstance(v8::Handle<v8::Value> val) {
745 if (!val->IsObject()) return false;
746 v8::Local<v8::Object> obj = val->ToObject();
dd52737 @stephank Provide a C++ Buffer constructor for external storage.
stephank authored
747
748 if (obj->GetIndexedPropertiesExternalArrayDataType() == kExternalUnsignedByteArray)
749 return true;
750
751 // Also check for SlowBuffers that are empty.
752 if (constructor_template->HasInstance(obj))
753 return true;
754
755 return false;
1cf538a @ry Work to get C++ fast buffers. incomplete
ry authored
756 }
757
488aff0 @ry Improve appendix markdown
ry authored
758
bf803f4 @ry Reimplment Buffers
ry authored
759 void Buffer::Initialize(Handle<Object> target) {
0afed52 @ry initial blobs
ry authored
760 HandleScope scope;
761
762 length_symbol = Persistent<String>::New(String::NewSymbol("length"));
5281f29 @ry Use new method of getting chars written for UTF8
ry authored
763 chars_written_sym = Persistent<String>::New(String::NewSymbol("_charsWritten"));
0afed52 @ry initial blobs
ry authored
764
bf803f4 @ry Reimplment Buffers
ry authored
765 Local<FunctionTemplate> t = FunctionTemplate::New(Buffer::New);
0afed52 @ry initial blobs
ry authored
766 constructor_template = Persistent<FunctionTemplate>::New(t);
767 constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
b8bfbda @ry Rename SlowBuffer in binding
ry authored
768 constructor_template->SetClassName(String::NewSymbol("SlowBuffer"));
0afed52 @ry initial blobs
ry authored
769
770 // copy free
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
771 NODE_SET_PROTOTYPE_METHOD(constructor_template, "binarySlice", Buffer::BinarySlice);
bf803f4 @ry Reimplment Buffers
ry authored
772 NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiSlice", Buffer::AsciiSlice);
528015e @ry Implement buffer.toString('base64')
ry authored
773 NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Slice", Buffer::Base64Slice);
9e101f2 UCS-2 support
Konstantin Käfer authored
774 NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Slice", Buffer::Ucs2Slice);
0afed52 @ry initial blobs
ry authored
775 // TODO NODE_SET_PROTOTYPE_METHOD(t, "utf16Slice", Utf16Slice);
bf803f4 @ry Reimplment Buffers
ry authored
776 // copy
777 NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Slice", Buffer::Utf8Slice);
0afed52 @ry initial blobs
ry authored
778
bf803f4 @ry Reimplment Buffers
ry authored
779 NODE_SET_PROTOTYPE_METHOD(constructor_template, "utf8Write", Buffer::Utf8Write);
780 NODE_SET_PROTOTYPE_METHOD(constructor_template, "asciiWrite", Buffer::AsciiWrite);
ac684f3 @ry Add legacy 'binary' encoding/decoding methods to Buffer
ry authored
781 NODE_SET_PROTOTYPE_METHOD(constructor_template, "binaryWrite", Buffer::BinaryWrite);
2c1ca40 @ry Implement buffer.write for base64
ry authored
782 NODE_SET_PROTOTYPE_METHOD(constructor_template, "base64Write", Buffer::Base64Write);
9e101f2 UCS-2 support
Konstantin Käfer authored
783 NODE_SET_PROTOTYPE_METHOD(constructor_template, "ucs2Write", Buffer::Ucs2Write);
5e1b7ca Add Buffer::fill method to do memset
Konstantin Käfer authored
784 NODE_SET_PROTOTYPE_METHOD(constructor_template, "fill", Buffer::Fill);
b72ffc0 @ry Add buffer.copy
ry authored
785 NODE_SET_PROTOTYPE_METHOD(constructor_template, "copy", Buffer::Copy);
bddd6e9 @ry Implement stream.send()
ry authored
786
4f56d8a @ry Rename Buffer.utf8Length to Buffer.utf8ByteLength
ry authored
787 NODE_SET_METHOD(constructor_template->GetFunction(),
3a993d8 @ry Buffer.utf8ByteLength -> Buffer.byteLength
ry authored
788 "byteLength",
789 Buffer::ByteLength);
488aff0 @ry Improve appendix markdown
ry authored
790 NODE_SET_METHOD(constructor_template->GetFunction(),
791 "makeFastBuffer",
792 Buffer::MakeFastBuffer);
bddd6e9 @ry Implement stream.send()
ry authored
793
b8bfbda @ry Rename SlowBuffer in binding
ry authored
794 target->Set(String::NewSymbol("SlowBuffer"), constructor_template->GetFunction());
0afed52 @ry initial blobs
ry authored
795 }
796
bf803f4 @ry Reimplment Buffers
ry authored
797
0afed52 @ry initial blobs
ry authored
798 } // namespace node
82daa46 @pquerna Move Buffer to extension model.
pquerna authored
799
cdcb111 @bnoordhuis Remove stray NODE_MODULE() semi-colons.
bnoordhuis authored
800 NODE_MODULE(node_buffer, node::Buffer::Initialize)
Something went wrong with that request. Please try again.