/ node_modules / pg-types / lib / binaryParsers.js
binaryParsers.js
  1  var parseInt64 = require('pg-int8');
  2  
  3  var parseBits = function(data, bits, offset, invert, callback) {
  4    offset = offset || 0;
  5    invert = invert || false;
  6    callback = callback || function(lastValue, newValue, bits) { return (lastValue * Math.pow(2, bits)) + newValue; };
  7    var offsetBytes = offset >> 3;
  8  
  9    var inv = function(value) {
 10      if (invert) {
 11        return ~value & 0xff;
 12      }
 13  
 14      return value;
 15    };
 16  
 17    // read first (maybe partial) byte
 18    var mask = 0xff;
 19    var firstBits = 8 - (offset % 8);
 20    if (bits < firstBits) {
 21      mask = (0xff << (8 - bits)) & 0xff;
 22      firstBits = bits;
 23    }
 24  
 25    if (offset) {
 26      mask = mask >> (offset % 8);
 27    }
 28  
 29    var result = 0;
 30    if ((offset % 8) + bits >= 8) {
 31      result = callback(0, inv(data[offsetBytes]) & mask, firstBits);
 32    }
 33  
 34    // read bytes
 35    var bytes = (bits + offset) >> 3;
 36    for (var i = offsetBytes + 1; i < bytes; i++) {
 37      result = callback(result, inv(data[i]), 8);
 38    }
 39  
 40    // bits to read, that are not a complete byte
 41    var lastBits = (bits + offset) % 8;
 42    if (lastBits > 0) {
 43      result = callback(result, inv(data[bytes]) >> (8 - lastBits), lastBits);
 44    }
 45  
 46    return result;
 47  };
 48  
 49  var parseFloatFromBits = function(data, precisionBits, exponentBits) {
 50    var bias = Math.pow(2, exponentBits - 1) - 1;
 51    var sign = parseBits(data, 1);
 52    var exponent = parseBits(data, exponentBits, 1);
 53  
 54    if (exponent === 0) {
 55      return 0;
 56    }
 57  
 58    // parse mantissa
 59    var precisionBitsCounter = 1;
 60    var parsePrecisionBits = function(lastValue, newValue, bits) {
 61      if (lastValue === 0) {
 62        lastValue = 1;
 63      }
 64  
 65      for (var i = 1; i <= bits; i++) {
 66        precisionBitsCounter /= 2;
 67        if ((newValue & (0x1 << (bits - i))) > 0) {
 68          lastValue += precisionBitsCounter;
 69        }
 70      }
 71  
 72      return lastValue;
 73    };
 74  
 75    var mantissa = parseBits(data, precisionBits, exponentBits + 1, false, parsePrecisionBits);
 76  
 77    // special cases
 78    if (exponent == (Math.pow(2, exponentBits + 1) - 1)) {
 79      if (mantissa === 0) {
 80        return (sign === 0) ? Infinity : -Infinity;
 81      }
 82  
 83      return NaN;
 84    }
 85  
 86    // normale number
 87    return ((sign === 0) ? 1 : -1) * Math.pow(2, exponent - bias) * mantissa;
 88  };
 89  
 90  var parseInt16 = function(value) {
 91    if (parseBits(value, 1) == 1) {
 92      return -1 * (parseBits(value, 15, 1, true) + 1);
 93    }
 94  
 95    return parseBits(value, 15, 1);
 96  };
 97  
 98  var parseInt32 = function(value) {
 99    if (parseBits(value, 1) == 1) {
100      return -1 * (parseBits(value, 31, 1, true) + 1);
101    }
102  
103    return parseBits(value, 31, 1);
104  };
105  
106  var parseFloat32 = function(value) {
107    return parseFloatFromBits(value, 23, 8);
108  };
109  
110  var parseFloat64 = function(value) {
111    return parseFloatFromBits(value, 52, 11);
112  };
113  
114  var parseNumeric = function(value) {
115    var sign = parseBits(value, 16, 32);
116    if (sign == 0xc000) {
117      return NaN;
118    }
119  
120    var weight = Math.pow(10000, parseBits(value, 16, 16));
121    var result = 0;
122  
123    var digits = [];
124    var ndigits = parseBits(value, 16);
125    for (var i = 0; i < ndigits; i++) {
126      result += parseBits(value, 16, 64 + (16 * i)) * weight;
127      weight /= 10000;
128    }
129  
130    var scale = Math.pow(10, parseBits(value, 16, 48));
131    return ((sign === 0) ? 1 : -1) * Math.round(result * scale) / scale;
132  };
133  
134  var parseDate = function(isUTC, value) {
135    var sign = parseBits(value, 1);
136    var rawValue = parseBits(value, 63, 1);
137  
138    // discard usecs and shift from 2000 to 1970
139    var result = new Date((((sign === 0) ? 1 : -1) * rawValue / 1000) + 946684800000);
140  
141    if (!isUTC) {
142      result.setTime(result.getTime() + result.getTimezoneOffset() * 60000);
143    }
144  
145    // add microseconds to the date
146    result.usec = rawValue % 1000;
147    result.getMicroSeconds = function() {
148      return this.usec;
149    };
150    result.setMicroSeconds = function(value) {
151      this.usec = value;
152    };
153    result.getUTCMicroSeconds = function() {
154      return this.usec;
155    };
156  
157    return result;
158  };
159  
160  var parseArray = function(value) {
161    var dim = parseBits(value, 32);
162  
163    var flags = parseBits(value, 32, 32);
164    var elementType = parseBits(value, 32, 64);
165  
166    var offset = 96;
167    var dims = [];
168    for (var i = 0; i < dim; i++) {
169      // parse dimension
170      dims[i] = parseBits(value, 32, offset);
171      offset += 32;
172  
173      // ignore lower bounds
174      offset += 32;
175    }
176  
177    var parseElement = function(elementType) {
178      // parse content length
179      var length = parseBits(value, 32, offset);
180      offset += 32;
181  
182      // parse null values
183      if (length == 0xffffffff) {
184        return null;
185      }
186  
187      var result;
188      if ((elementType == 0x17) || (elementType == 0x14)) {
189        // int/bigint
190        result = parseBits(value, length * 8, offset);
191        offset += length * 8;
192        return result;
193      }
194      else if (elementType == 0x19) {
195        // string
196        result = value.toString(this.encoding, offset >> 3, (offset += (length << 3)) >> 3);
197        return result;
198      }
199      else {
200        console.log("ERROR: ElementType not implemented: " + elementType);
201      }
202    };
203  
204    var parse = function(dimension, elementType) {
205      var array = [];
206      var i;
207  
208      if (dimension.length > 1) {
209        var count = dimension.shift();
210        for (i = 0; i < count; i++) {
211          array[i] = parse(dimension, elementType);
212        }
213        dimension.unshift(count);
214      }
215      else {
216        for (i = 0; i < dimension[0]; i++) {
217          array[i] = parseElement(elementType);
218        }
219      }
220  
221      return array;
222    };
223  
224    return parse(dims, elementType);
225  };
226  
227  var parseText = function(value) {
228    return value.toString('utf8');
229  };
230  
231  var parseBool = function(value) {
232    if(value === null) return null;
233    return (parseBits(value, 8) > 0);
234  };
235  
236  var init = function(register) {
237    register(20, parseInt64);
238    register(21, parseInt16);
239    register(23, parseInt32);
240    register(26, parseInt32);
241    register(1700, parseNumeric);
242    register(700, parseFloat32);
243    register(701, parseFloat64);
244    register(16, parseBool);
245    register(1114, parseDate.bind(null, false));
246    register(1184, parseDate.bind(null, true));
247    register(1000, parseArray);
248    register(1007, parseArray);
249    register(1016, parseArray);
250    register(1008, parseArray);
251    register(1009, parseArray);
252    register(25, parseText);
253  };
254  
255  module.exports = {
256    init: init
257  };