added unit testing, and started implementing unit tests...phew
This commit is contained in:
+121
@@ -0,0 +1,121 @@
|
||||
/*!
|
||||
* BufferUtil originally from:
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
#include <v8.h>
|
||||
#include <node.h>
|
||||
#include <node_version.h>
|
||||
#include <node_buffer.h>
|
||||
#include <node_object_wrap.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
class BufferUtil : public ObjectWrap
|
||||
{
|
||||
public:
|
||||
|
||||
static void Initialize(v8::Handle<v8::Object> target)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
|
||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
Nan::SetMethod(t, "unmask", BufferUtil::Unmask);
|
||||
Nan::SetMethod(t, "mask", BufferUtil::Mask);
|
||||
Nan::SetMethod(t, "merge", BufferUtil::Merge);
|
||||
Nan::Set(target, Nan::New<String>("BufferUtil").ToLocalChecked(), t->GetFunction());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static NAN_METHOD(New)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
BufferUtil* bufferUtil = new BufferUtil();
|
||||
bufferUtil->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Merge)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Local<Object> bufferObj = info[0]->ToObject();
|
||||
char* buffer = Buffer::Data(bufferObj);
|
||||
Local<Array> array = Local<Array>::Cast(info[1]);
|
||||
unsigned int arrayLength = array->Length();
|
||||
size_t offset = 0;
|
||||
unsigned int i;
|
||||
for (i = 0; i < arrayLength; ++i) {
|
||||
Local<Object> src = array->Get(i)->ToObject();
|
||||
size_t length = Buffer::Length(src);
|
||||
memcpy(buffer + offset, Buffer::Data(src), length);
|
||||
offset += length;
|
||||
}
|
||||
info.GetReturnValue().Set(Nan::True());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Unmask)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Local<Object> buffer_obj = info[0]->ToObject();
|
||||
size_t length = Buffer::Length(buffer_obj);
|
||||
Local<Object> mask_obj = info[1]->ToObject();
|
||||
unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
|
||||
unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
|
||||
size_t len32 = length / 4;
|
||||
unsigned int i;
|
||||
for (i = 0; i < len32; ++i) *(from + i) ^= *mask;
|
||||
from += i;
|
||||
switch (length % 4) {
|
||||
case 3: *((unsigned char*)from+2) = *((unsigned char*)from+2) ^ ((unsigned char*)mask)[2];
|
||||
case 2: *((unsigned char*)from+1) = *((unsigned char*)from+1) ^ ((unsigned char*)mask)[1];
|
||||
case 1: *((unsigned char*)from ) = *((unsigned char*)from ) ^ ((unsigned char*)mask)[0];
|
||||
case 0:;
|
||||
}
|
||||
info.GetReturnValue().Set(Nan::True());
|
||||
}
|
||||
|
||||
static NAN_METHOD(Mask)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Local<Object> buffer_obj = info[0]->ToObject();
|
||||
Local<Object> mask_obj = info[1]->ToObject();
|
||||
unsigned int *mask = (unsigned int*)Buffer::Data(mask_obj);
|
||||
Local<Object> output_obj = info[2]->ToObject();
|
||||
unsigned int dataOffset = info[3]->Int32Value();
|
||||
unsigned int length = info[4]->Int32Value();
|
||||
unsigned int* to = (unsigned int*)(Buffer::Data(output_obj) + dataOffset);
|
||||
unsigned int* from = (unsigned int*)Buffer::Data(buffer_obj);
|
||||
unsigned int len32 = length / 4;
|
||||
unsigned int i;
|
||||
for (i = 0; i < len32; ++i) *(to + i) = *(from + i) ^ *mask;
|
||||
to += i;
|
||||
from += i;
|
||||
switch (length % 4) {
|
||||
case 3: *((unsigned char*)to+2) = *((unsigned char*)from+2) ^ *((unsigned char*)mask+2);
|
||||
case 2: *((unsigned char*)to+1) = *((unsigned char*)from+1) ^ *((unsigned char*)mask+1);
|
||||
case 1: *((unsigned char*)to ) = *((unsigned char*)from ) ^ *((unsigned char*)mask);
|
||||
case 0:;
|
||||
}
|
||||
info.GetReturnValue().Set(Nan::True());
|
||||
}
|
||||
};
|
||||
|
||||
#if !NODE_VERSION_AT_LEAST(0,10,0)
|
||||
extern "C"
|
||||
#endif
|
||||
void init (Handle<Object> target)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
BufferUtil::Initialize(target);
|
||||
}
|
||||
|
||||
NODE_MODULE(bufferutil, init)
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*!
|
||||
* UTF-8 Validation Code originally from:
|
||||
* ws: a node.js websocket client
|
||||
* Copyright(c) 2015 Einar Otto Stangvik <einaros@gmail.com>
|
||||
* MIT Licensed
|
||||
*/
|
||||
|
||||
#include <v8.h>
|
||||
#include <node.h>
|
||||
#include <node_version.h>
|
||||
#include <node_buffer.h>
|
||||
#include <node_object_wrap.h>
|
||||
#include <stdlib.h>
|
||||
#include <wchar.h>
|
||||
#include <stdio.h>
|
||||
#include "nan.h"
|
||||
|
||||
using namespace v8;
|
||||
using namespace node;
|
||||
|
||||
#define UNI_SUR_HIGH_START (uint32_t) 0xD800
|
||||
#define UNI_SUR_LOW_END (uint32_t) 0xDFFF
|
||||
#define UNI_REPLACEMENT_CHAR (uint32_t) 0x0000FFFD
|
||||
#define UNI_MAX_LEGAL_UTF32 (uint32_t) 0x0010FFFF
|
||||
|
||||
static const uint8_t trailingBytesForUTF8[256] = {
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
|
||||
2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
|
||||
};
|
||||
|
||||
static const uint32_t offsetsFromUTF8[6] = {
|
||||
0x00000000, 0x00003080, 0x000E2080,
|
||||
0x03C82080, 0xFA082080, 0x82082080
|
||||
};
|
||||
|
||||
static int isLegalUTF8(const uint8_t *source, const int length)
|
||||
{
|
||||
uint8_t a;
|
||||
const uint8_t *srcptr = source+length;
|
||||
switch (length) {
|
||||
default: return 0;
|
||||
/* Everything else falls through when "true"... */
|
||||
/* RFC3629 makes 5 & 6 bytes UTF-8 illegal
|
||||
case 6: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 5: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0; */
|
||||
case 4: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 3: if ((a = (*--srcptr)) < 0x80 || a > 0xBF) return 0;
|
||||
case 2: if ((a = (*--srcptr)) > 0xBF) return 0;
|
||||
switch (*source) {
|
||||
/* no fall-through in this inner switch */
|
||||
case 0xE0: if (a < 0xA0) return 0; break;
|
||||
case 0xED: if (a > 0x9F) return 0; break;
|
||||
case 0xF0: if (a < 0x90) return 0; break;
|
||||
case 0xF4: if (a > 0x8F) return 0; break;
|
||||
default: if (a < 0x80) return 0;
|
||||
}
|
||||
|
||||
case 1: if (*source >= 0x80 && *source < 0xC2) return 0;
|
||||
}
|
||||
if (*source > 0xF4) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int is_valid_utf8 (size_t len, char *value)
|
||||
{
|
||||
/* is the string valid UTF-8? */
|
||||
for (unsigned int i = 0; i < len; i++) {
|
||||
uint32_t ch = 0;
|
||||
uint8_t extrabytes = trailingBytesForUTF8[(uint8_t) value[i]];
|
||||
|
||||
if (extrabytes + i >= len)
|
||||
return 0;
|
||||
|
||||
if (isLegalUTF8 ((uint8_t *) (value + i), extrabytes + 1) == 0) return 0;
|
||||
|
||||
switch (extrabytes) {
|
||||
case 5 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 4 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 3 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 2 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 1 : ch += (uint8_t) value[i++]; ch <<= 6;
|
||||
case 0 : ch += (uint8_t) value[i];
|
||||
}
|
||||
|
||||
ch -= offsetsFromUTF8[extrabytes];
|
||||
|
||||
if (ch <= UNI_MAX_LEGAL_UTF32) {
|
||||
if (ch >= UNI_SUR_HIGH_START && ch <= UNI_SUR_LOW_END)
|
||||
return 0;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
class Validation : public ObjectWrap
|
||||
{
|
||||
public:
|
||||
|
||||
static void Initialize(v8::Handle<v8::Object> target)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Local<FunctionTemplate> t = Nan::New<FunctionTemplate>(New);
|
||||
t->InstanceTemplate()->SetInternalFieldCount(1);
|
||||
Nan::SetMethod(t, "isValidUTF8", Validation::IsValidUTF8);
|
||||
Nan::Set(target, Nan::New<String>("Validation").ToLocalChecked(), t->GetFunction());
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
static NAN_METHOD(New)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Validation* validation = new Validation();
|
||||
validation->Wrap(info.This());
|
||||
info.GetReturnValue().Set(info.This());
|
||||
}
|
||||
|
||||
static NAN_METHOD(IsValidUTF8)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
if (!Buffer::HasInstance(info[0])) {
|
||||
return Nan::ThrowTypeError("First argument needs to be a buffer");
|
||||
}
|
||||
Local<Object> buffer_obj = info[0]->ToObject();
|
||||
char *buffer_data = Buffer::Data(buffer_obj);
|
||||
size_t buffer_length = Buffer::Length(buffer_obj);
|
||||
info.GetReturnValue().Set(is_valid_utf8(buffer_length, buffer_data) == 1 ? Nan::True() : Nan::False());
|
||||
}
|
||||
};
|
||||
#if !NODE_VERSION_AT_LEAST(0,10,0)
|
||||
extern "C"
|
||||
#endif
|
||||
void init (Handle<Object> target)
|
||||
{
|
||||
Nan::HandleScope scope;
|
||||
Validation::Initialize(target);
|
||||
}
|
||||
|
||||
NODE_MODULE(validation, init)
|
||||
Reference in New Issue
Block a user