UNPKG

tedious

Version:

A TDS driver, for connecting to MS SQLServer databases.

479 lines (452 loc) 12.9 kB
// Generated by CoffeeScript 1.7.1 var DEFAULT_ENCODING, MAX, MONEY_DIVISOR, NULL, PLP_NULL, THREE_AND_A_THIRD, UNKNOWN_PLP_LEN, guidParser, iconv, parse, readBinary, readChars, readDate, readDateTime, readDateTime2, readDateTimeOffset, readMax, readMaxBinary, readMaxChars, readMaxNChars, readNChars, readSmallDateTime, readTime, sprintf; iconv = require('iconv-lite'); sprintf = require('sprintf').sprintf; guidParser = require('./guid-parser'); require('./buffertools'); NULL = (1 << 16) - 1; MAX = (1 << 16) - 1; THREE_AND_A_THIRD = 3 + (1 / 3); MONEY_DIVISOR = 10000; PLP_NULL = new Buffer([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); UNKNOWN_PLP_LEN = new Buffer([0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]); DEFAULT_ENCODING = 'utf8'; parse = function(buffer, metaData, options) { var codepage, dataLength, high, low, sign, textPointerLength, textPointerNull, type, value; value = void 0; dataLength = void 0; textPointerNull = void 0; type = metaData.type; if (type.hasTextPointerAndTimestamp) { textPointerLength = buffer.readUInt8(); if (textPointerLength !== 0) { buffer.readBuffer(textPointerLength); buffer.readBuffer(8); } else { dataLength = 0; textPointerNull = true; } } if (!dataLength && dataLength !== 0) { switch (type.id & 0x30) { case 0x10: dataLength = 0; break; case 0x20: if (metaData.dataLength !== MAX) { switch (type.dataLengthLength) { case 0: dataLength = void 0; break; case 1: dataLength = buffer.readUInt8(); break; case 2: dataLength = buffer.readUInt16LE(); break; case 4: dataLength = buffer.readUInt32LE(); break; default: throw Error("Unsupported dataLengthLength " + type.dataLengthLength + " for data type " + type.name); } } break; case 0x30: dataLength = 1 << ((type.id & 0x0C) >> 2); } } switch (type.name) { case 'Null': value = null; break; case 'TinyInt': value = buffer.readUInt8(); break; case 'Int': value = buffer.readInt32LE(); break; case 'SmallInt': value = buffer.readInt16LE(); break; case 'BigInt': value = buffer.readAsStringInt64LE(); break; case 'IntN': switch (dataLength) { case 0: value = null; break; case 1: value = buffer.readUInt8(); break; case 2: value = buffer.readInt16LE(); break; case 4: value = buffer.readInt32LE(); break; case 8: value = buffer.readAsStringInt64LE(); break; default: throw new Error("Unsupported dataLength " + dataLength + " for IntN"); } break; case 'Real': value = buffer.readFloatLE(); break; case 'Float': value = buffer.readDoubleLE(); break; case 'FloatN': switch (dataLength) { case 0: value = null; break; case 4: value = buffer.readFloatLE(); break; case 8: value = buffer.readDoubleLE(); break; default: throw new Error("Unsupported dataLength " + dataLength + " for FloatN"); } break; case 'Money': case 'SmallMoney': case 'MoneyN': switch (dataLength) { case 0: value = null; break; case 4: value = buffer.readInt32LE() / MONEY_DIVISOR; break; case 8: high = buffer.readInt32LE(); low = buffer.readUInt32LE(); value = low + (0x100000000 * high); value /= MONEY_DIVISOR; break; default: throw new Error("Unsupported dataLength " + dataLength + " for MoneyN"); } break; case 'Bit': value = !!buffer.readUInt8(); break; case 'BitN': switch (dataLength) { case 0: value = null; break; case 1: value = !!buffer.readUInt8(); } break; case 'VarChar': case 'Char': codepage = metaData.collation.codepage; if (metaData.dataLength === MAX) { value = readMaxChars(buffer, codepage); } else { value = readChars(buffer, dataLength, codepage); } break; case 'NVarChar': case 'NChar': if (metaData.dataLength === MAX) { value = readMaxNChars(buffer); } else { value = readNChars(buffer, dataLength); } break; case 'VarBinary': case 'Binary': if (metaData.dataLength === MAX) { value = readMaxBinary(buffer); } else { value = readBinary(buffer, dataLength); } break; case 'Text': if (textPointerNull) { value = null; } else { value = readChars(buffer, dataLength, metaData.collation.codepage); } break; case 'NText': if (textPointerNull) { value = null; } else { value = readNChars(buffer, dataLength); } break; case 'Image': if (textPointerNull) { value = null; } else { value = readBinary(buffer, dataLength); } break; case 'Xml': value = readMaxNChars(buffer); break; case 'SmallDateTime': value = readSmallDateTime(buffer, options.useUTC); break; case 'DateTime': value = readDateTime(buffer, options.useUTC); break; case 'DateTimeN': switch (dataLength) { case 0: value = null; break; case 4: value = readSmallDateTime(buffer, options.useUTC); break; case 8: value = readDateTime(buffer, options.useUTC); } break; case 'TimeN': if ((dataLength = buffer.readUInt8()) === 0) { value = null; } else { value = readTime(buffer, dataLength, metaData.scale); } break; case 'DateN': if ((dataLength = buffer.readUInt8()) === 0) { value = null; } else { value = readDate(buffer); } break; case 'DateTime2N': if ((dataLength = buffer.readUInt8()) === 0) { value = null; } else { value = readDateTime2(buffer, dataLength, metaData.scale); } break; case 'DateTimeOffsetN': if ((dataLength = buffer.readUInt8()) === 0) { value = null; } else { value = readDateTimeOffset(buffer, dataLength, metaData.scale); } break; case 'NumericN': case 'DecimalN': if (dataLength === 0) { value = null; } else { sign = buffer.readUInt8() === 1 ? 1 : -1; switch (dataLength - 1) { case 4: value = buffer.readUInt32LE(); break; case 8: value = buffer.readUNumeric64LE(); break; case 12: value = buffer.readUNumeric96LE(); break; case 16: value = buffer.readUNumeric128LE(); break; default: throw new Error(sprintf('Unsupported numeric size %d at offset 0x%04X', dataLength - 1, buffer.position)); break; } value *= sign; value /= Math.pow(10, metaData.scale); } break; case 'UniqueIdentifierN': switch (dataLength) { case 0: value = null; break; case 0x10: value = guidParser.arrayToGuid(buffer.readArray(0x10)); break; default: throw new Error(sprintf('Unsupported guid size %d at offset 0x%04X', dataLength - 1, buffer.position)); } break; case 'UDT': value = readMaxBinary(buffer); break; default: throw new Error(sprintf('Unrecognised type %s at offset 0x%04X', type.name, buffer.position)); break; } return value; }; readBinary = function(buffer, dataLength) { if (dataLength === NULL) { return null; } else { return buffer.readBuffer(dataLength); } }; readChars = function(buffer, dataLength, codepage) { if (codepage == null) { codepage = DEFAULT_ENCODING; } if (dataLength === NULL) { return null; } else { return iconv.decode(buffer.readBuffer(dataLength), codepage); } }; readNChars = function(buffer, dataLength) { if (dataLength === NULL) { return null; } else { return buffer.readString(dataLength, 'ucs2'); } }; readMaxBinary = function(buffer) { return readMax(buffer, function(valueBuffer) { return valueBuffer; }); }; readMaxChars = function(buffer, codepage) { if (codepage == null) { codepage = DEFAULT_ENCODING; } return readMax(buffer, function(valueBuffer) { return iconv.decode(valueBuffer, codepage); }); }; readMaxNChars = function(buffer) { return readMax(buffer, function(valueBuffer) { return valueBuffer.toString('ucs2'); }); }; readMax = function(buffer, decodeFunction) { var chunk, chunkLength, chunks, expectedLength, length, position, type, valueBuffer, _i, _len; type = buffer.readBuffer(8); if (type.equals(PLP_NULL)) { return null; } else { if (type.equals(UNKNOWN_PLP_LEN)) { expectedLength = void 0; } else { buffer.rollback(); expectedLength = buffer.readUInt64LE(); } length = 0; chunks = []; chunkLength = buffer.readUInt32LE(); while (chunkLength !== 0) { length += chunkLength; chunks.push(buffer.readBuffer(chunkLength)); chunkLength = buffer.readUInt32LE(); } if (expectedLength) { if (length !== expectedLength) { throw new Error("Partially Length-prefixed Bytes unmatched lengths : expected " + expectedLength + ", but got " + length + " bytes"); } } valueBuffer = new Buffer(length); position = 0; for (_i = 0, _len = chunks.length; _i < _len; _i++) { chunk = chunks[_i]; chunk.copy(valueBuffer, position, 0); position += chunk.length; } return decodeFunction(valueBuffer); } }; readSmallDateTime = function(buffer, useUTC) { var days, minutes, value; days = buffer.readUInt16LE(); minutes = buffer.readUInt16LE(); if (useUTC) { value = new Date(Date.UTC(1900, 0, 1)); value.setUTCDate(value.getUTCDate() + days); value.setUTCMinutes(value.getUTCMinutes() + minutes); } else { value = new Date(1900, 0, 1); value.setDate(value.getDate() + days); value.setMinutes(value.getMinutes() + minutes); } return value; }; readDateTime = function(buffer, useUTC) { var days, milliseconds, threeHundredthsOfSecond, value; days = buffer.readInt32LE(); threeHundredthsOfSecond = buffer.readUInt32LE(); milliseconds = threeHundredthsOfSecond * THREE_AND_A_THIRD; if (useUTC) { value = new Date(Date.UTC(1900, 0, 1)); value.setUTCDate(value.getUTCDate() + days); value.setUTCMilliseconds(value.getUTCMilliseconds() + milliseconds); } else { value = new Date(1900, 0, 1); value.setDate(value.getDate() + days); value.setMilliseconds(value.getMilliseconds() + milliseconds); } return value; }; readTime = function(buffer, dataLength, scale) { var date, i, value, _i, _ref; switch (dataLength) { case 3: value = buffer.readUInt24LE(); break; case 4: value = buffer.readUInt32LE(); break; case 5: value = buffer.readUInt40LE(); } if (scale < 7) { for (i = _i = _ref = scale + 1; _ref <= 7 ? _i <= 7 : _i >= 7; i = _ref <= 7 ? ++_i : --_i) { value *= 10; } } date = new Date(Date.UTC(1970, 0, 1, 0, 0, 0, value / 10000)); Object.defineProperty(date, "nanosecondsDelta", { enumerable: false, value: (value % 10000) / Math.pow(10, 7) }); return date; }; readDate = function(buffer) { var days; days = buffer.readUInt24LE(); return new Date(Date.UTC(2000, 0, days - 730118)); }; readDateTime2 = function(buffer, dataLength, scale) { var date, days, time; time = readTime(buffer, dataLength - 3, scale); days = buffer.readUInt24LE(); date = new Date(Date.UTC(2000, 0, days - 730118, 0, 0, 0, +time)); Object.defineProperty(date, "nanosecondsDelta", { enumerable: false, value: time.nanosecondsDelta }); return date; }; readDateTimeOffset = function(buffer, dataLength, scale) { var date, days, offset, time; time = readTime(buffer, dataLength - 5, scale); days = buffer.readUInt24LE(); offset = buffer.readInt16LE(); date = new Date(Date.UTC(2000, 0, days - 730118, 0, 0, 0, +time)); Object.defineProperty(date, "nanosecondsDelta", { enumerable: false, value: time.nanosecondsDelta }); return date; }; module.exports = parse;