| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491 | 
							- var PacketHeader = require('./PacketHeader');
 
- var BigNumber    = require('bignumber.js');
 
- var Buffer       = require('safe-buffer').Buffer;
 
- var BufferList   = require('./BufferList');
 
- var MAX_PACKET_LENGTH    = Math.pow(2, 24) - 1;
 
- var MUL_32BIT            = Math.pow(2, 32);
 
- var PACKET_HEADER_LENGTH = 4;
 
- module.exports = Parser;
 
- function Parser(options) {
 
-   options = options || {};
 
-   this._supportBigNumbers = options.config && options.config.supportBigNumbers;
 
-   this._buffer            = Buffer.alloc(0);
 
-   this._nextBuffers       = new BufferList();
 
-   this._longPacketBuffers = new BufferList();
 
-   this._offset            = 0;
 
-   this._packetEnd         = null;
 
-   this._packetHeader      = null;
 
-   this._packetOffset      = null;
 
-   this._onError           = options.onError || function(err) { throw err; };
 
-   this._onPacket          = options.onPacket || function() {};
 
-   this._nextPacketNumber  = 0;
 
-   this._encoding          = 'utf-8';
 
-   this._paused            = false;
 
- }
 
- Parser.prototype.write = function write(chunk) {
 
-   this._nextBuffers.push(chunk);
 
-   while (!this._paused) {
 
-     var packetHeader = this._tryReadPacketHeader();
 
-     if (!packetHeader) {
 
-       break;
 
-     }
 
-     if (!this._combineNextBuffers(packetHeader.length)) {
 
-       break;
 
-     }
 
-     this._parsePacket(packetHeader);
 
-   }
 
- };
 
- Parser.prototype.append = function append(chunk) {
 
-   if (!chunk || chunk.length === 0) {
 
-     return;
 
-   }
 
-   // Calculate slice ranges
 
-   var sliceEnd    = this._buffer.length;
 
-   var sliceStart  = this._packetOffset === null
 
-     ? this._offset
 
-     : this._packetOffset;
 
-   var sliceLength = sliceEnd - sliceStart;
 
-   // Get chunk data
 
-   var buffer = null;
 
-   var chunks = !(chunk instanceof Array || Array.isArray(chunk)) ? [chunk] : chunk;
 
-   var length = 0;
 
-   var offset = 0;
 
-   for (var i = 0; i < chunks.length; i++) {
 
-     length += chunks[i].length;
 
-   }
 
-   if (sliceLength !== 0) {
 
-     // Create a new Buffer
 
-     buffer = Buffer.allocUnsafe(sliceLength + length);
 
-     offset = 0;
 
-     // Copy data slice
 
-     offset += this._buffer.copy(buffer, 0, sliceStart, sliceEnd);
 
-     // Copy chunks
 
-     for (var i = 0; i < chunks.length; i++) {
 
-       offset += chunks[i].copy(buffer, offset);
 
-     }
 
-   } else if (chunks.length > 1) {
 
-     // Create a new Buffer
 
-     buffer = Buffer.allocUnsafe(length);
 
-     offset = 0;
 
-     // Copy chunks
 
-     for (var i = 0; i < chunks.length; i++) {
 
-       offset += chunks[i].copy(buffer, offset);
 
-     }
 
-   } else {
 
-     // Buffer is the only chunk
 
-     buffer = chunks[0];
 
-   }
 
-   // Adjust data-tracking pointers
 
-   this._buffer       = buffer;
 
-   this._offset       = this._offset - sliceStart;
 
-   this._packetEnd    = this._packetEnd !== null
 
-     ? this._packetEnd - sliceStart
 
-     : null;
 
-   this._packetOffset = this._packetOffset !== null
 
-     ? this._packetOffset - sliceStart
 
-     : null;
 
- };
 
- Parser.prototype.pause = function() {
 
-   this._paused = true;
 
- };
 
- Parser.prototype.resume = function() {
 
-   this._paused = false;
 
-   // nextTick() to avoid entering write() multiple times within the same stack
 
-   // which would cause problems as write manipulates the state of the object.
 
-   process.nextTick(this.write.bind(this));
 
- };
 
- Parser.prototype.peak = function peak(offset) {
 
-   return this._buffer[this._offset + (offset >>> 0)];
 
- };
 
- Parser.prototype.parseUnsignedNumber = function parseUnsignedNumber(bytes) {
 
-   if (bytes === 1) {
 
-     return this._buffer[this._offset++];
 
-   }
 
-   var buffer = this._buffer;
 
-   var offset = this._offset + bytes - 1;
 
-   var value  = 0;
 
-   if (bytes > 4) {
 
-     var err    = new Error('parseUnsignedNumber: Supports only up to 4 bytes');
 
-     err.offset = (this._offset - this._packetOffset - 1);
 
-     err.code   = 'PARSER_UNSIGNED_TOO_LONG';
 
-     throw err;
 
-   }
 
-   while (offset >= this._offset) {
 
-     value = ((value << 8) | buffer[offset]) >>> 0;
 
-     offset--;
 
-   }
 
-   this._offset += bytes;
 
-   return value;
 
- };
 
- Parser.prototype.parseLengthCodedString = function() {
 
-   var length = this.parseLengthCodedNumber();
 
-   if (length === null) {
 
-     return null;
 
-   }
 
-   return this.parseString(length);
 
- };
 
- Parser.prototype.parseLengthCodedBuffer = function() {
 
-   var length = this.parseLengthCodedNumber();
 
-   if (length === null) {
 
-     return null;
 
-   }
 
-   return this.parseBuffer(length);
 
- };
 
- Parser.prototype.parseLengthCodedNumber = function parseLengthCodedNumber() {
 
-   if (this._offset >= this._buffer.length) {
 
-     var err    = new Error('Parser: read past end');
 
-     err.offset = (this._offset - this._packetOffset);
 
-     err.code   = 'PARSER_READ_PAST_END';
 
-     throw err;
 
-   }
 
-   var bits = this._buffer[this._offset++];
 
-   if (bits <= 250) {
 
-     return bits;
 
-   }
 
-   switch (bits) {
 
-     case 251:
 
-       return null;
 
-     case 252:
 
-       return this.parseUnsignedNumber(2);
 
-     case 253:
 
-       return this.parseUnsignedNumber(3);
 
-     case 254:
 
-       break;
 
-     default:
 
-       var err    = new Error('Unexpected first byte' + (bits ? ': 0x' + bits.toString(16) : ''));
 
-       err.offset = (this._offset - this._packetOffset - 1);
 
-       err.code   = 'PARSER_BAD_LENGTH_BYTE';
 
-       throw err;
 
-   }
 
-   var low = this.parseUnsignedNumber(4);
 
-   var high = this.parseUnsignedNumber(4);
 
-   var value;
 
-   if (high >>> 21) {
 
-     value = BigNumber(MUL_32BIT).times(high).plus(low).toString();
 
-     if (this._supportBigNumbers) {
 
-       return value;
 
-     }
 
-     var err    = new Error(
 
-       'parseLengthCodedNumber: JS precision range exceeded, ' +
 
-       'number is >= 53 bit: "' + value + '"'
 
-     );
 
-     err.offset = (this._offset - this._packetOffset - 8);
 
-     err.code   = 'PARSER_JS_PRECISION_RANGE_EXCEEDED';
 
-     throw err;
 
-   }
 
-   value = low + (MUL_32BIT * high);
 
-   return value;
 
- };
 
- Parser.prototype.parseFiller = function(length) {
 
-   return this.parseBuffer(length);
 
- };
 
- Parser.prototype.parseNullTerminatedBuffer = function() {
 
-   var end      = this._nullByteOffset();
 
-   var value    = this._buffer.slice(this._offset, end);
 
-   this._offset = end + 1;
 
-   return value;
 
- };
 
- Parser.prototype.parseNullTerminatedString = function() {
 
-   var end      = this._nullByteOffset();
 
-   var value    = this._buffer.toString(this._encoding, this._offset, end);
 
-   this._offset = end + 1;
 
-   return value;
 
- };
 
- Parser.prototype._nullByteOffset = function() {
 
-   var offset = this._offset;
 
-   while (this._buffer[offset] !== 0x00) {
 
-     offset++;
 
-     if (offset >= this._buffer.length) {
 
-       var err    = new Error('Offset of null terminated string not found.');
 
-       err.offset = (this._offset - this._packetOffset);
 
-       err.code   = 'PARSER_MISSING_NULL_BYTE';
 
-       throw err;
 
-     }
 
-   }
 
-   return offset;
 
- };
 
- Parser.prototype.parsePacketTerminatedBuffer = function parsePacketTerminatedBuffer() {
 
-   var length = this._packetEnd - this._offset;
 
-   return this.parseBuffer(length);
 
- };
 
- Parser.prototype.parsePacketTerminatedString = function() {
 
-   var length = this._packetEnd - this._offset;
 
-   return this.parseString(length);
 
- };
 
- Parser.prototype.parseBuffer = function(length) {
 
-   var response = Buffer.alloc(length);
 
-   this._buffer.copy(response, 0, this._offset, this._offset + length);
 
-   this._offset += length;
 
-   return response;
 
- };
 
- Parser.prototype.parseString = function(length) {
 
-   var offset = this._offset;
 
-   var end = offset + length;
 
-   var value = this._buffer.toString(this._encoding, offset, end);
 
-   this._offset = end;
 
-   return value;
 
- };
 
- Parser.prototype.parseGeometryValue = function() {
 
-   var buffer = this.parseLengthCodedBuffer();
 
-   var offset = 4;
 
-   if (buffer === null || !buffer.length) {
 
-     return null;
 
-   }
 
-   function parseGeometry() {
 
-     var result = null;
 
-     var byteOrder = buffer.readUInt8(offset); offset += 1;
 
-     var wkbType = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
 
-     switch (wkbType) {
 
-       case 1: // WKBPoint
 
-         var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-         var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-         result = {x: x, y: y};
 
-         break;
 
-       case 2: // WKBLineString
 
-         var numPoints = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
 
-         result = [];
 
-         for (var i = numPoints; i > 0; i--) {
 
-           var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-           var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-           result.push({x: x, y: y});
 
-         }
 
-         break;
 
-       case 3: // WKBPolygon
 
-         var numRings = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
 
-         result = [];
 
-         for (var i = numRings; i > 0; i--) {
 
-           var numPoints = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
 
-           var line = [];
 
-           for (var j = numPoints; j > 0; j--) {
 
-             var x = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-             var y = byteOrder ? buffer.readDoubleLE(offset) : buffer.readDoubleBE(offset); offset += 8;
 
-             line.push({x: x, y: y});
 
-           }
 
-           result.push(line);
 
-         }
 
-         break;
 
-       case 4: // WKBMultiPoint
 
-       case 5: // WKBMultiLineString
 
-       case 6: // WKBMultiPolygon
 
-       case 7: // WKBGeometryCollection
 
-         var num = byteOrder ? buffer.readUInt32LE(offset) : buffer.readUInt32BE(offset); offset += 4;
 
-         var result = [];
 
-         for (var i = num; i > 0; i--) {
 
-           result.push(parseGeometry());
 
-         }
 
-         break;
 
-     }
 
-     return result;
 
-   }
 
-   return parseGeometry();
 
- };
 
- Parser.prototype.reachedPacketEnd = function() {
 
-   return this._offset === this._packetEnd;
 
- };
 
- Parser.prototype.incrementPacketNumber = function() {
 
-   var currentPacketNumber = this._nextPacketNumber;
 
-   this._nextPacketNumber = (this._nextPacketNumber + 1) % 256;
 
-   return currentPacketNumber;
 
- };
 
- Parser.prototype.resetPacketNumber = function() {
 
-   this._nextPacketNumber = 0;
 
- };
 
- Parser.prototype.packetLength = function packetLength() {
 
-   if (!this._packetHeader) {
 
-     return null;
 
-   }
 
-   return this._packetHeader.length + this._longPacketBuffers.size;
 
- };
 
- Parser.prototype._combineNextBuffers = function _combineNextBuffers(bytes) {
 
-   var length = this._buffer.length - this._offset;
 
-   if (length >= bytes) {
 
-     return true;
 
-   }
 
-   if ((length + this._nextBuffers.size) < bytes) {
 
-     return false;
 
-   }
 
-   var buffers     = [];
 
-   var bytesNeeded = bytes - length;
 
-   while (bytesNeeded > 0) {
 
-     var buffer = this._nextBuffers.shift();
 
-     buffers.push(buffer);
 
-     bytesNeeded -= buffer.length;
 
-   }
 
-   this.append(buffers);
 
-   return true;
 
- };
 
- Parser.prototype._combineLongPacketBuffers = function _combineLongPacketBuffers() {
 
-   if (!this._longPacketBuffers.size) {
 
-     return;
 
-   }
 
-   // Calculate bytes
 
-   var remainingBytes      = this._buffer.length - this._offset;
 
-   var trailingPacketBytes = this._buffer.length - this._packetEnd;
 
-   // Create buffer
 
-   var buf    = null;
 
-   var buffer = Buffer.allocUnsafe(remainingBytes + this._longPacketBuffers.size);
 
-   var offset = 0;
 
-   // Copy long buffers
 
-   while ((buf = this._longPacketBuffers.shift())) {
 
-     offset += buf.copy(buffer, offset);
 
-   }
 
-   // Copy remaining bytes
 
-   this._buffer.copy(buffer, offset, this._offset);
 
-   this._buffer       = buffer;
 
-   this._offset       = 0;
 
-   this._packetEnd    = this._buffer.length - trailingPacketBytes;
 
-   this._packetOffset = 0;
 
- };
 
- Parser.prototype._parsePacket = function _parsePacket(packetHeader) {
 
-   this._packetEnd    = this._offset + packetHeader.length;
 
-   this._packetOffset = this._offset;
 
-   if (packetHeader.length === MAX_PACKET_LENGTH) {
 
-     this._longPacketBuffers.push(this._buffer.slice(this._packetOffset, this._packetEnd));
 
-     this._advanceToNextPacket();
 
-     return;
 
-   }
 
-   this._combineLongPacketBuffers();
 
-   var hadException = true;
 
-   try {
 
-     this._onPacket(packetHeader);
 
-     hadException = false;
 
-   } catch (err) {
 
-     if (!err || typeof err.code !== 'string' || err.code.substr(0, 7) !== 'PARSER_') {
 
-       throw err; // Rethrow non-MySQL errors
 
-     }
 
-     // Pass down parser errors
 
-     this._onError(err);
 
-     hadException = false;
 
-   } finally {
 
-     this._advanceToNextPacket();
 
-     // If there was an exception, the parser while loop will be broken out
 
-     // of after the finally block. So schedule a blank write to re-enter it
 
-     // to continue parsing any bytes that may already have been received.
 
-     if (hadException) {
 
-       process.nextTick(this.write.bind(this));
 
-     }
 
-   }
 
- };
 
- Parser.prototype._tryReadPacketHeader = function _tryReadPacketHeader() {
 
-   if (this._packetHeader) {
 
-     return this._packetHeader;
 
-   }
 
-   if (!this._combineNextBuffers(PACKET_HEADER_LENGTH)) {
 
-     return null;
 
-   }
 
-   this._packetHeader = new PacketHeader(
 
-     this.parseUnsignedNumber(3),
 
-     this.parseUnsignedNumber(1)
 
-   );
 
-   if (this._packetHeader.number !== this._nextPacketNumber) {
 
-     var err = new Error(
 
-       'Packets out of order. Got: ' + this._packetHeader.number + ' ' +
 
-       'Expected: ' + this._nextPacketNumber
 
-     );
 
-     err.code  = 'PROTOCOL_PACKETS_OUT_OF_ORDER';
 
-     err.fatal = true;
 
-     this._onError(err);
 
-   }
 
-   this.incrementPacketNumber();
 
-   return this._packetHeader;
 
- };
 
- Parser.prototype._advanceToNextPacket = function() {
 
-   this._offset       = this._packetEnd;
 
-   this._packetHeader = null;
 
-   this._packetEnd    = null;
 
-   this._packetOffset = null;
 
- };
 
 
  |