354 lines
8.8 KiB
JavaScript
354 lines
8.8 KiB
JavaScript
'use strict'
|
|
|
|
var C = require('./constants')
|
|
|
|
exports.CONSTANTS = C
|
|
exports.STATUS_CODES = require('./status-codes')
|
|
|
|
exports.request = {
|
|
decode: function () {
|
|
var obj = decode.apply(null, arguments)
|
|
exports.request.decode.bytes = decode.bytes
|
|
obj.operationId = obj._oprationIdOrStatusCode
|
|
delete obj._oprationIdOrStatusCode
|
|
return obj
|
|
},
|
|
encode: encode,
|
|
encodingLength: encodingLength
|
|
}
|
|
|
|
exports.response = {
|
|
decode: function () {
|
|
var obj = decode.apply(null, arguments)
|
|
exports.response.decode.bytes = decode.bytes
|
|
obj.statusCode = obj._oprationIdOrStatusCode
|
|
delete obj._oprationIdOrStatusCode
|
|
return obj
|
|
},
|
|
encode: encode,
|
|
encodingLength: encodingLength
|
|
}
|
|
|
|
function decode (buf, start, end) {
|
|
if (!start) start = 0
|
|
if (!end) end = buf.length
|
|
var offset = start
|
|
|
|
var obj = {
|
|
version: {},
|
|
groups: []
|
|
}
|
|
|
|
obj.version.major = buf.readInt8(offset++)
|
|
obj.version.minor = buf.readInt8(offset++)
|
|
obj._oprationIdOrStatusCode = buf.readInt16BE(offset)
|
|
offset += 2
|
|
obj.requestId = buf.readInt32BE(offset)
|
|
offset += 4
|
|
|
|
// attribute groups
|
|
var tag = buf.readInt8(offset++) // delimiter-tag
|
|
while (tag !== C.END_OF_ATTRIBUTES_TAG && offset < end) {
|
|
var group = { tag: tag, attributes: [] }
|
|
|
|
// attribute-with-one-value or additional-value
|
|
tag = buf.readInt8(offset++) // value-tag
|
|
while (tag > 0x0f) {
|
|
var name = str.decode(buf, offset)
|
|
offset += str.decode.bytes
|
|
|
|
var val
|
|
switch (tag) {
|
|
case C.INTEGER:
|
|
val = tint.decode(buf, offset)
|
|
offset += tint.decode.bytes
|
|
break
|
|
case C.BOOLEAN:
|
|
val = tbool.decode(buf, offset)
|
|
offset += tbool.decode.bytes
|
|
break
|
|
case C.ENUM:
|
|
val = tenum.decode(buf, offset)
|
|
offset += tenum.decode.bytes
|
|
break
|
|
case C.DATE_TIME:
|
|
val = tdatetime.decode(buf, offset)
|
|
offset += tdatetime.decode.bytes
|
|
break
|
|
case C.TEXT_WITH_LANG:
|
|
case C.NAME_WITH_LANG:
|
|
val = langstr.decode(buf, offset)
|
|
offset += langstr.decode.bytes
|
|
break
|
|
default:
|
|
val = str.decode(buf, offset)
|
|
offset += str.decode.bytes
|
|
}
|
|
|
|
if (!name) {
|
|
attr.value.push(val)
|
|
} else {
|
|
var attr = { tag: tag, name: name, value: [val] }
|
|
group.attributes.push(attr)
|
|
}
|
|
|
|
tag = buf.readInt8(offset++) // delimiter-tag or value-tag
|
|
}
|
|
|
|
obj.groups.push(group)
|
|
}
|
|
|
|
decode.bytes = offset - start
|
|
|
|
return obj
|
|
}
|
|
|
|
function encode (obj, buf, offset) {
|
|
if (!buf) buf = new Buffer(encodingLength(obj))
|
|
if (!offset) offset = 0
|
|
var oldOffset = offset
|
|
|
|
buf.writeInt8(obj.version ? obj.version.major : 1, offset++)
|
|
buf.writeInt8(obj.version ? obj.version.minor : 1, offset++)
|
|
|
|
buf.writeInt16BE(obj.statusCode === undefined ? obj.operationId : obj.statusCode, offset)
|
|
offset += 2
|
|
|
|
buf.writeInt32BE(obj.requestId, offset)
|
|
offset += 4
|
|
|
|
if (obj.groups) {
|
|
obj.groups.forEach(function (group) {
|
|
buf.writeInt8(group.tag, offset++)
|
|
|
|
group.attributes.forEach(function (attr) {
|
|
var value = Array.isArray(attr.value) ? attr.value : [attr.value]
|
|
value.forEach(function (val, i) {
|
|
buf.writeInt8(attr.tag, offset++)
|
|
|
|
str.encode(i ? '' : attr.name, buf, offset)
|
|
offset += str.encode.bytes
|
|
|
|
switch (attr.tag) {
|
|
case C.INTEGER:
|
|
tint.encode(val, buf, offset)
|
|
offset += tint.encode.bytes
|
|
break
|
|
case C.BOOLEAN:
|
|
tbool.encode(val, buf, offset)
|
|
offset += tbool.encode.bytes
|
|
break
|
|
case C.ENUM:
|
|
tenum.encode(val, buf, offset)
|
|
offset += tenum.encode.bytes
|
|
break
|
|
case C.DATE_TIME:
|
|
tdatetime.encode(val, buf, offset)
|
|
offset += tdatetime.encode.bytes
|
|
break
|
|
case C.TEXT_WITH_LANG:
|
|
case C.NAME_WITH_LANG:
|
|
langstr.encode(val, buf, offset)
|
|
offset += langstr.encode.bytes
|
|
break
|
|
default:
|
|
str.encode(val, buf, offset)
|
|
offset += str.encode.bytes
|
|
}
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
buf.writeInt8(C.END_OF_ATTRIBUTES_TAG, offset++)
|
|
|
|
if (obj.data) offset += obj.data.copy(buf, offset)
|
|
|
|
encode.bytes = offset - oldOffset
|
|
|
|
return buf
|
|
}
|
|
|
|
function encodingLength (obj) {
|
|
var len = 8 // version-number + status-code + request-id
|
|
|
|
if (obj.groups) {
|
|
len += obj.groups.reduce(function (len, group) {
|
|
len += 1 // begin-attribute-group-tag
|
|
len += group.attributes.reduce(function (len, attr) {
|
|
var value = Array.isArray(attr.value) ? attr.value : [attr.value]
|
|
len += value.reduce(function (len, val) {
|
|
len += 1 // value-tag
|
|
len += str.encodingLength(len === 1 ? attr.name : '')
|
|
|
|
switch (attr.tag) {
|
|
case C.INTEGER: return len + tint.encodingLength(val)
|
|
case C.BOOLEAN: return len + tbool.encodingLength(val)
|
|
case C.ENUM: return len + tenum.encodingLength(val)
|
|
case C.DATE_TIME: return len + tdatetime.encodingLength(val)
|
|
case C.TEXT_WITH_LANG:
|
|
case C.NAME_WITH_LANG: return len + langstr.encodingLength(val)
|
|
default: return len + str.encodingLength(val)
|
|
}
|
|
}, 0)
|
|
|
|
return len
|
|
}, 0)
|
|
return len
|
|
}, 0)
|
|
}
|
|
|
|
len++ // end-of-attributes-tag
|
|
|
|
if (obj.data) len += obj.data.length
|
|
|
|
return len
|
|
}
|
|
|
|
var tint = {}
|
|
|
|
tint.decode = function (buf, offset) {
|
|
var i = buf.readInt32BE(offset + 2)
|
|
tint.decode.bytes = 6
|
|
return i
|
|
}
|
|
|
|
tint.encode = function (i, buf, offset) {
|
|
buf.writeInt16BE(4, offset)
|
|
buf.writeInt32BE(i, offset + 2)
|
|
tint.encode.bytes = 6
|
|
return buf
|
|
}
|
|
|
|
tint.encodingLength = function (s) {
|
|
return 6
|
|
}
|
|
|
|
var tenum = {}
|
|
|
|
tenum.decode = function (buf, offset) {
|
|
var i = buf.readInt32BE(offset + 2)
|
|
tenum.decode.bytes = 6
|
|
return i
|
|
}
|
|
|
|
tenum.encode = function (i, buf, offset) {
|
|
buf.writeInt16BE(4, offset)
|
|
buf.writeInt32BE(i, offset + 2)
|
|
tenum.encode.bytes = 6
|
|
return buf
|
|
}
|
|
|
|
tenum.encodingLength = function (s) {
|
|
return 6
|
|
}
|
|
|
|
var tbool = {}
|
|
|
|
tbool.decode = function (buf, offset) {
|
|
var b = buf.readInt8(offset + 2) === C.TRUE
|
|
tbool.decode.bytes = 3
|
|
return b
|
|
}
|
|
|
|
tbool.encode = function (b, buf, offset) {
|
|
buf.writeInt16BE(1, offset)
|
|
buf.writeInt8(b ? C.TRUE : C.FALSE, offset + 2)
|
|
tbool.encode.bytes = 3
|
|
return buf
|
|
}
|
|
|
|
tbool.encodingLength = function (s) {
|
|
return 3
|
|
}
|
|
|
|
var langstr = {}
|
|
|
|
langstr.decode = function (buf, offset) {
|
|
var oldOffset = offset
|
|
offset += 2
|
|
var lang = str.decode(buf, offset)
|
|
offset += str.decode.bytes
|
|
var val = str.decode(buf, offset)
|
|
offset += str.decode.bytes
|
|
langstr.decode.bytes = offset - oldOffset
|
|
return { lang: lang, value: val }
|
|
}
|
|
|
|
langstr.encode = function (obj, buf, offset) {
|
|
str.encode(obj.lang, buf, offset + 2)
|
|
var len = str.encode.bytes
|
|
str.encode(obj.value, buf, offset + 2 + len)
|
|
len += str.encode.bytes
|
|
buf.writeInt16BE(len, offset)
|
|
langstr.encode.bytes = len + 2
|
|
return buf
|
|
}
|
|
|
|
langstr.encodingLength = function (obj) {
|
|
return Buffer.byteLength(obj.lang) + Buffer.byteLength(obj.value) + 6
|
|
}
|
|
|
|
var str = {}
|
|
|
|
str.decode = function (buf, offset) {
|
|
var len = buf.readInt16BE(offset)
|
|
var s = buf.toString('utf-8', offset + 2, offset + 2 + len)
|
|
str.decode.bytes = len + 2
|
|
return s
|
|
}
|
|
|
|
str.encode = function (s, buf, offset) {
|
|
var len = buf.write(s, offset + 2)
|
|
buf.writeInt16BE(len, offset)
|
|
str.encode.bytes = len + 2
|
|
return buf
|
|
}
|
|
|
|
str.encodingLength = function (s) {
|
|
return Buffer.byteLength(s) + 2
|
|
}
|
|
|
|
var tdatetime = {}
|
|
|
|
tdatetime.decode = function (buf, offset) {
|
|
var drift = (buf.readInt8(offset + 11) * 60) + buf.readInt8(offset + 12)
|
|
if (buf.slice(offset + 10, offset + 11) === '+') drift = drift * -1
|
|
|
|
var d = new Date(Date.UTC(
|
|
buf.readInt16BE(offset + 2),
|
|
buf.readInt8(offset + 4) - 1,
|
|
buf.readInt8(offset + 5),
|
|
buf.readInt8(offset + 6),
|
|
buf.readInt8(offset + 7) + drift,
|
|
buf.readInt8(offset + 8),
|
|
buf.readInt8(offset + 9) * 100
|
|
))
|
|
|
|
tdatetime.decode.bytes = 13
|
|
|
|
return d
|
|
}
|
|
|
|
tdatetime.encode = function (d, buf, offset) {
|
|
buf.writeInt16BE(11, offset)
|
|
buf.writeInt16BE(d.getFullYear(), offset + 2)
|
|
buf.writeInt8(d.getMonth() + 1, offset + 4)
|
|
buf.writeInt8(d.getDate(), offset + 5)
|
|
buf.writeInt8(d.getHours(), offset + 6)
|
|
buf.writeInt8(d.getMinutes(), offset + 7)
|
|
buf.writeInt8(d.getSeconds(), offset + 8)
|
|
buf.writeInt8(Math.floor(d.getMilliseconds() / 100), offset + 9)
|
|
buf.write(d.getTimezoneOffset() > 0 ? '-' : '+', offset + 10)
|
|
buf.writeInt8(d.getTimezoneOffset() / 60, offset + 11)
|
|
buf.writeInt8(d.getTimezoneOffset() % 60, offset + 12)
|
|
|
|
tdatetime.encode.bytes = 13
|
|
|
|
return buf
|
|
}
|
|
|
|
tdatetime.encodingLength = function (s) {
|
|
return 13
|
|
}
|