1 var DATA_TYPES = require('./../constants/DataTypes'),
  2   CAS = require('../constants/CASConstants');
  3 
  4 module.exports = PacketReader;
  5 
  6 /**
  7  * PacketReader
  8  * @constructor
  9  */
 10 function PacketReader() {
 11   this._buffer = null;
 12   this._offset = 0;
 13 }
 14 
 15 /**
 16  * Write a buffer value to the internal buffer
 17  * @param buffer
 18  */
 19 PacketReader.prototype.write = function (buffer) {
 20   this._append(buffer);
 21 };
 22 
 23 //TODO Optimize the performance of this function
 24 /**
 25  * Append a buffer value to the internal buffer
 26  * @param newBuffer
 27  */
 28 PacketReader.prototype._append = function (newBuffer) {
 29   var oldBuffer = this._buffer;
 30 
 31   if (!oldBuffer) {
 32     this._buffer = newBuffer;
 33     return;
 34   }
 35 
 36   var bytesRemaining = this._bytesRemaining();
 37   var newLength = bytesRemaining + newBuffer.length;
 38 
 39   var combinedBuffer = (this._offset > newLength)
 40     ? oldBuffer.slice(0, newLength)
 41     : new Buffer(newLength);
 42 
 43   oldBuffer.copy(combinedBuffer, 0, this._offset);
 44   newBuffer.copy(combinedBuffer, bytesRemaining);
 45 
 46   this._buffer = combinedBuffer;
 47   this._offset = 0;
 48 };
 49 
 50 /**
 51  * Returns an short value from the internal buffer
 52  * @return {Number}
 53  */
 54 PacketReader.prototype._parseShort = function () {
 55   var value = 0;
 56 
 57   for (var i = DATA_TYPES.SHORT_SIZEOF - 1; i >= 0; i--) {
 58     value += this._buffer[this._offset++] * Math.pow(256, i);
 59   }
 60 
 61   if (value & 0x8000) {
 62     return value - 0xFFFF - 1;
 63   } else {
 64     return value;
 65   }
 66 };
 67 
 68 /**
 69  * Returns an integer value from the internal buffer
 70  * @return {Number}
 71  */
 72 PacketReader.prototype._parseInt = function () {
 73   var value = 0;
 74 
 75   for (var i = DATA_TYPES.INT_SIZEOF - 1; i >= 0; i--) {
 76     value += this._buffer[this._offset++] * Math.pow(256, i);
 77   }
 78 
 79   if (value & 0x80000000) {
 80     return value - 0xFFFFFFFF - 1;
 81   } else {
 82     return value;
 83   }
 84 };
 85 
 86 /**
 87  * Returns a byte value from the internal buffer
 88  * @return {Number}
 89  */
 90 PacketReader.prototype._parseByte = function () {
 91   return this._buffer[this._offset++];
 92 };
 93 
 94 /**
 95  * Returns a bytes array from the internal buffer
 96  * @param bytesCount
 97  * @return {Array}
 98  */
 99 PacketReader.prototype._parseBytes = function (bytesCount) {
100   var buffer = this._buffer.slice(this._offset, this._offset + bytesCount);
101 
102   this._offset += bytesCount;
103 
104   return buffer;
105 };
106 
107 /**
108  * Returns a buffer object from the internal buffer
109  * @param bytesCount
110  * @return {*}
111  */
112 PacketReader.prototype._parseBuffer = function (bytesCount) {
113   var buffer = this._buffer.slice(this._offset, this._offset + bytesCount);
114 
115   this._offset += bytesCount;
116 
117   return buffer;
118 };
119 
120 /**
121  * Returns a string value from the internal buffer
122  * @param bytesCount
123  * @return {Buffer}
124  */
125 PacketReader.prototype._parseString = function (bytesCount) {
126   if (bytesCount <= 0) {
127     return '';
128   }
129 
130   var start = this._offset;
131   var end = start + bytesCount;
132   var buffer = this._buffer.slice(start, end);
133 
134   var value = '';
135   for (var i = 0; i < buffer.length; i++) {
136     value += String.fromCharCode(buffer[i]);
137   }
138 
139   this._offset = end;
140 
141   return value;
142 };
143 
144 /**
145  * Returns a string value from the internal buffer
146  * @return {String}
147  */
148 PacketReader.prototype._parseNullTerminatedString = function (length) {
149   if (length <= 0) {
150     return '';
151   }
152 
153   var valueLen = length - 1; //get the actual null-terminated string length
154   var buffer = this._buffer.slice(this._offset, this._offset + valueLen);
155   var value = buffer.toString();
156 
157   this._offset += valueLen;
158   this._parseByte(); //read also the null-terminate
159 
160   return value;
161 };
162 
163 /**
164  * Returns a date value from the internal buffer
165  * @return {Date}
166  */
167 PacketReader.prototype._parseDate = function () {
168   var year = this._parseShort();
169   var month = this._parseShort();
170   var day = this._parseShort();
171   var hour = 0;
172   var min = 0;
173   var sec = 0;
174   var msec = 0;
175 
176   return new Date(year, month, day, hour, min, sec, msec);
177 };
178 
179 /**
180  * Returns a datetime value from the internal buffer
181  * @return {Date}
182  */
183 PacketReader.prototype._parseDateTime = function () {
184   var year = this._parseShort();
185   var month = this._parseShort();
186   var day = this._parseShort();
187   var hour = this._parseShort();
188   var min = this._parseShort();
189   var sec = this._parseShort();
190   var msec = this._parseShort();
191 
192   return new Date(year, month, day, hour, min, sec, msec);
193 };
194 
195 /**
196  * Returns a time value from the internal buffer
197  * @return {Date}
198  */
199 PacketReader.prototype._parseTime = function () {
200   var year = 0;
201   var month = 0;
202   var day = 0;
203   var hour = this._parseShort();
204   var min = this._parseShort();
205   var sec = this._parseShort();
206   var msec = 0;
207 
208   return new Date(year, month, day, hour, min, sec, msec);
209 };
210 
211 /**
212  * Returns a timestamp value from the internal buffer
213  * @return {Date}
214  */
215 PacketReader.prototype._parseTimeStamp = function () {
216   var year = this._parseShort();
217   var month = this._parseShort();
218   var day = this._parseShort();
219   var hour = this._parseShort();
220   var min = this._parseShort();
221   var sec = this._parseShort();
222   var msec = 0;
223 
224   return new Date(year, month, day, hour, min, sec, msec);
225 };
226 
227 /**
228  * Returns a char value from the internal buffer
229  * @return {String}
230  */
231 PacketReader.prototype._parseChar = function () {
232   var val = this._parseByte();
233 
234   return String.fromCharCode(val);
235 };
236 
237 /**
238  * Returns a Long value from the internal buffer
239  * @return {Number}
240  */
241 PacketReader.prototype._parseLong = function () {
242   var value = 0;
243 
244   for (var i = DATA_TYPES.LONG_SIZEOF - 1; i >= 0; i--) {
245     value += this._buffer[this._offset++] * Math.pow(256, i);
246   }
247 
248   if (value & 0x8000000000000000) {
249     return value - 0xFFFFFFFFFFFFFFFF - 1;
250   } else {
251     return value;
252   }
253 };
254 
255 /**
256  * Returns a double value from the internal buffer
257  * @return {Number}
258  */
259 PacketReader.prototype._parseDouble = function () {
260   var value = this._buffer.readDoubleBE(this._offset);
261   this._offset += DATA_TYPES.DOUBLE_SIZEOF;
262   return value;
263 };
264 
265 /**
266  * Returns a floating point value from the internal buffer
267  * @return {Number}
268  */
269 PacketReader.prototype._parseFloat = function () {
270   var value = this._buffer.readFloatBE(this._offset);
271   this._offset += DATA_TYPES.FLOAT_SIZEOF;
272   return value;
273 };
274 
275 /**
276  * Returns a Numeric value from the internal buffer
277  * @return {Number}
278  */
279 PacketReader.prototype._parseNumeric = function (size) {
280   return parseFloat(this._parseNullTerminatedString(size));
281 };
282 
283 /**
284  * Returns a Object value from the internal buffer
285  * @return {String}
286  */
287 PacketReader.prototype._parseObject = function () {
288   return 'OID:@' + this._parseInt() + '|' + this._parseShort() + '|' + this._parseShort();
289 };
290 
291 /**
292  * Returns a BLOB object from the internal buffer
293  * @return {Buffer}
294  */
295 PacketReader.prototype._parseBlob = function (size) {
296   var packedLobHandle = this._parseBytes(size);
297   var lobSizeBuffer = packedLobHandle.slice(DATA_TYPES.INT_SIZEOF, DATA_TYPES.INT_SIZEOF + DATA_TYPES.LONG_SIZEOF);
298   var lobSize = 0;
299 
300   for (var i = DATA_TYPES.LONG_SIZEOF - 1; i >= 0; i--) {
301     lobSize += lobSizeBuffer[DATA_TYPES.LONG_SIZEOF - i - 1] * Math.pow(256, i);
302   }
303 
304   return {
305     lobType : CAS.CUBRIDDataType.CCI_U_TYPE_BLOB, //Clob tyte
306     packedLobHandle: packedLobHandle,
307     lobLength : lobSize
308   }
309 };
310 
311 /**
312  * Returns a CLOB object from the internal buffer
313  * @return {String}
314  */
315 PacketReader.prototype._parseClob = function (size) {
316   var packedLobHandle = this._parseBytes(size);
317   var lobSizeBuffer = packedLobHandle.slice(DATA_TYPES.INT_SIZEOF, DATA_TYPES.INT_SIZEOF + DATA_TYPES.LONG_SIZEOF);
318   var lobSize = 0;
319 
320   for (var i = DATA_TYPES.LONG_SIZEOF - 1; i >= 0; i--) {
321     lobSize += lobSizeBuffer[DATA_TYPES.LONG_SIZEOF - i - 1] * Math.pow(256, i);
322   }
323 
324   return {
325     lobType : CAS.CUBRIDDataType.CCI_U_TYPE_CLOB, //Clob tyte
326     packedLobHandle: packedLobHandle,
327     lobLength : lobSize
328   }
329 };
330 
331 /**
332  * Returns a sequence of values from the internal buffer
333  * @return {Array}
334  */
335 PacketReader.prototype._parseSequence = function () {
336   var count = this._parseInt();
337   var size = this._parseInt();
338   this._offset += count * size;
339 
340   return null; //Not supported
341 };
342 
343 /**
344  * Returns a ResultSet from the internal buffer
345  * @return {String}
346  */
347 PacketReader.prototype._parseResultSet = function () {
348   this._offset += DATA_TYPES.RESULTSET_SIZEOF;
349 
350   return null; //Not supported
351 };
352 
353 /**
354  * Return the number of bytes remaining unparsed/unread in the buffer
355  * @return {Number}
356  */
357 PacketReader.prototype._bytesRemaining = function () {
358   return this._buffer.length - this._offset;
359 };
360 
361 /**
362  * Return the internal buffer length
363  * @return {Number}
364  */
365 PacketReader.prototype._packetLength = function () {
366   return this._buffer.length;
367 };
368 
369