You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
269 lines
7.0 KiB
269 lines
7.0 KiB
// write-type.js |
|
|
|
var IS_ARRAY = require("isarray"); |
|
var Int64Buffer = require("int64-buffer"); |
|
var Uint64BE = Int64Buffer.Uint64BE; |
|
var Int64BE = Int64Buffer.Int64BE; |
|
|
|
var Bufferish = require("./bufferish"); |
|
var BufferProto = require("./bufferish-proto"); |
|
var WriteToken = require("./write-token"); |
|
var uint8 = require("./write-uint8").uint8; |
|
var ExtBuffer = require("./ext-buffer").ExtBuffer; |
|
|
|
var HAS_UINT8ARRAY = ("undefined" !== typeof Uint8Array); |
|
var HAS_MAP = ("undefined" !== typeof Map); |
|
|
|
var extmap = []; |
|
extmap[1] = 0xd4; |
|
extmap[2] = 0xd5; |
|
extmap[4] = 0xd6; |
|
extmap[8] = 0xd7; |
|
extmap[16] = 0xd8; |
|
|
|
exports.getWriteType = getWriteType; |
|
|
|
function getWriteType(options) { |
|
var token = WriteToken.getWriteToken(options); |
|
var useraw = options && options.useraw; |
|
var binarraybuffer = HAS_UINT8ARRAY && options && options.binarraybuffer; |
|
var isBuffer = binarraybuffer ? Bufferish.isArrayBuffer : Bufferish.isBuffer; |
|
var bin = binarraybuffer ? bin_arraybuffer : bin_buffer; |
|
var usemap = HAS_MAP && options && options.usemap; |
|
var map = usemap ? map_to_map : obj_to_map; |
|
|
|
var writeType = { |
|
"boolean": bool, |
|
"function": nil, |
|
"number": number, |
|
"object": (useraw ? object_raw : object), |
|
"string": _string(useraw ? raw_head_size : str_head_size), |
|
"symbol": nil, |
|
"undefined": nil |
|
}; |
|
|
|
return writeType; |
|
|
|
// false -- 0xc2 |
|
// true -- 0xc3 |
|
function bool(encoder, value) { |
|
var type = value ? 0xc3 : 0xc2; |
|
token[type](encoder, value); |
|
} |
|
|
|
function number(encoder, value) { |
|
var ivalue = value | 0; |
|
var type; |
|
if (value !== ivalue) { |
|
// float 64 -- 0xcb |
|
type = 0xcb; |
|
token[type](encoder, value); |
|
return; |
|
} else if (-0x20 <= ivalue && ivalue <= 0x7F) { |
|
// positive fixint -- 0x00 - 0x7f |
|
// negative fixint -- 0xe0 - 0xff |
|
type = ivalue & 0xFF; |
|
} else if (0 <= ivalue) { |
|
// uint 8 -- 0xcc |
|
// uint 16 -- 0xcd |
|
// uint 32 -- 0xce |
|
type = (ivalue <= 0xFF) ? 0xcc : (ivalue <= 0xFFFF) ? 0xcd : 0xce; |
|
} else { |
|
// int 8 -- 0xd0 |
|
// int 16 -- 0xd1 |
|
// int 32 -- 0xd2 |
|
type = (-0x80 <= ivalue) ? 0xd0 : (-0x8000 <= ivalue) ? 0xd1 : 0xd2; |
|
} |
|
token[type](encoder, ivalue); |
|
} |
|
|
|
// uint 64 -- 0xcf |
|
function uint64(encoder, value) { |
|
var type = 0xcf; |
|
token[type](encoder, value.toArray()); |
|
} |
|
|
|
// int 64 -- 0xd3 |
|
function int64(encoder, value) { |
|
var type = 0xd3; |
|
token[type](encoder, value.toArray()); |
|
} |
|
|
|
// str 8 -- 0xd9 |
|
// str 16 -- 0xda |
|
// str 32 -- 0xdb |
|
// fixstr -- 0xa0 - 0xbf |
|
function str_head_size(length) { |
|
return (length < 32) ? 1 : (length <= 0xFF) ? 2 : (length <= 0xFFFF) ? 3 : 5; |
|
} |
|
|
|
// raw 16 -- 0xda |
|
// raw 32 -- 0xdb |
|
// fixraw -- 0xa0 - 0xbf |
|
function raw_head_size(length) { |
|
return (length < 32) ? 1 : (length <= 0xFFFF) ? 3 : 5; |
|
} |
|
|
|
function _string(head_size) { |
|
return string; |
|
|
|
function string(encoder, value) { |
|
// prepare buffer |
|
var length = value.length; |
|
var maxsize = 5 + length * 3; |
|
encoder.offset = encoder.reserve(maxsize); |
|
var buffer = encoder.buffer; |
|
|
|
// expected header size |
|
var expected = head_size(length); |
|
|
|
// expected start point |
|
var start = encoder.offset + expected; |
|
|
|
// write string |
|
length = BufferProto.write.call(buffer, value, start); |
|
|
|
// actual header size |
|
var actual = head_size(length); |
|
|
|
// move content when needed |
|
if (expected !== actual) { |
|
var targetStart = start + actual - expected; |
|
var end = start + length; |
|
BufferProto.copy.call(buffer, buffer, targetStart, start, end); |
|
} |
|
|
|
// write header |
|
var type = (actual === 1) ? (0xa0 + length) : (actual <= 3) ? (0xd7 + actual) : 0xdb; |
|
token[type](encoder, length); |
|
|
|
// move cursor |
|
encoder.offset += length; |
|
} |
|
} |
|
|
|
function object(encoder, value) { |
|
// null |
|
if (value === null) return nil(encoder, value); |
|
|
|
// Buffer |
|
if (isBuffer(value)) return bin(encoder, value); |
|
|
|
// Array |
|
if (IS_ARRAY(value)) return array(encoder, value); |
|
|
|
// int64-buffer objects |
|
if (Uint64BE.isUint64BE(value)) return uint64(encoder, value); |
|
if (Int64BE.isInt64BE(value)) return int64(encoder, value); |
|
|
|
// ext formats |
|
var packer = encoder.codec.getExtPacker(value); |
|
if (packer) value = packer(value); |
|
if (value instanceof ExtBuffer) return ext(encoder, value); |
|
|
|
// plain old Objects or Map |
|
map(encoder, value); |
|
} |
|
|
|
function object_raw(encoder, value) { |
|
// Buffer |
|
if (isBuffer(value)) return raw(encoder, value); |
|
|
|
// others |
|
object(encoder, value); |
|
} |
|
|
|
// nil -- 0xc0 |
|
function nil(encoder, value) { |
|
var type = 0xc0; |
|
token[type](encoder, value); |
|
} |
|
|
|
// fixarray -- 0x90 - 0x9f |
|
// array 16 -- 0xdc |
|
// array 32 -- 0xdd |
|
function array(encoder, value) { |
|
var length = value.length; |
|
var type = (length < 16) ? (0x90 + length) : (length <= 0xFFFF) ? 0xdc : 0xdd; |
|
token[type](encoder, length); |
|
|
|
var encode = encoder.codec.encode; |
|
for (var i = 0; i < length; i++) { |
|
encode(encoder, value[i]); |
|
} |
|
} |
|
|
|
// bin 8 -- 0xc4 |
|
// bin 16 -- 0xc5 |
|
// bin 32 -- 0xc6 |
|
function bin_buffer(encoder, value) { |
|
var length = value.length; |
|
var type = (length < 0xFF) ? 0xc4 : (length <= 0xFFFF) ? 0xc5 : 0xc6; |
|
token[type](encoder, length); |
|
encoder.send(value); |
|
} |
|
|
|
function bin_arraybuffer(encoder, value) { |
|
bin_buffer(encoder, new Uint8Array(value)); |
|
} |
|
|
|
// fixext 1 -- 0xd4 |
|
// fixext 2 -- 0xd5 |
|
// fixext 4 -- 0xd6 |
|
// fixext 8 -- 0xd7 |
|
// fixext 16 -- 0xd8 |
|
// ext 8 -- 0xc7 |
|
// ext 16 -- 0xc8 |
|
// ext 32 -- 0xc9 |
|
function ext(encoder, value) { |
|
var buffer = value.buffer; |
|
var length = buffer.length; |
|
var type = extmap[length] || ((length < 0xFF) ? 0xc7 : (length <= 0xFFFF) ? 0xc8 : 0xc9); |
|
token[type](encoder, length); |
|
uint8[value.type](encoder); |
|
encoder.send(buffer); |
|
} |
|
|
|
// fixmap -- 0x80 - 0x8f |
|
// map 16 -- 0xde |
|
// map 32 -- 0xdf |
|
function obj_to_map(encoder, value) { |
|
var keys = Object.keys(value); |
|
var length = keys.length; |
|
var type = (length < 16) ? (0x80 + length) : (length <= 0xFFFF) ? 0xde : 0xdf; |
|
token[type](encoder, length); |
|
|
|
var encode = encoder.codec.encode; |
|
keys.forEach(function(key) { |
|
encode(encoder, key); |
|
encode(encoder, value[key]); |
|
}); |
|
} |
|
|
|
// fixmap -- 0x80 - 0x8f |
|
// map 16 -- 0xde |
|
// map 32 -- 0xdf |
|
function map_to_map(encoder, value) { |
|
if (!(value instanceof Map)) return obj_to_map(encoder, value); |
|
|
|
var length = value.size; |
|
var type = (length < 16) ? (0x80 + length) : (length <= 0xFFFF) ? 0xde : 0xdf; |
|
token[type](encoder, length); |
|
|
|
var encode = encoder.codec.encode; |
|
value.forEach(function(val, key, m) { |
|
encode(encoder, key); |
|
encode(encoder, val); |
|
}); |
|
} |
|
|
|
// raw 16 -- 0xda |
|
// raw 32 -- 0xdb |
|
// fixraw -- 0xa0 - 0xbf |
|
function raw(encoder, value) { |
|
var length = value.length; |
|
var type = (length < 32) ? (0xa0 + length) : (length <= 0xFFFF) ? 0xda : 0xdb; |
|
token[type](encoder, length); |
|
encoder.send(value); |
|
} |
|
}
|
|
|