index.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. //binary data writer tuned for creating
  2. //postgres message packets as effeciently as possible by reusing the
  3. //same buffer to avoid memcpy and limit memory allocations
  4. var Writer = module.exports = function (size) {
  5. this.size = size || 1024;
  6. this.buffer = Buffer.alloc(this.size + 5);
  7. this.offset = 5;
  8. this.headerPosition = 0;
  9. };
  10. //resizes internal buffer if not enough size left
  11. Writer.prototype._ensure = function (size) {
  12. var remaining = this.buffer.length - this.offset;
  13. if (remaining < size) {
  14. var oldBuffer = this.buffer;
  15. // exponential growth factor of around ~ 1.5
  16. // https://stackoverflow.com/questions/2269063/buffer-growth-strategy
  17. var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size;
  18. this.buffer = Buffer.alloc(newSize);
  19. oldBuffer.copy(this.buffer);
  20. }
  21. };
  22. Writer.prototype.addInt32 = function (num) {
  23. this._ensure(4);
  24. this.buffer[this.offset++] = (num >>> 24 & 0xFF);
  25. this.buffer[this.offset++] = (num >>> 16 & 0xFF);
  26. this.buffer[this.offset++] = (num >>> 8 & 0xFF);
  27. this.buffer[this.offset++] = (num >>> 0 & 0xFF);
  28. return this;
  29. };
  30. Writer.prototype.addInt16 = function (num) {
  31. this._ensure(2);
  32. this.buffer[this.offset++] = (num >>> 8 & 0xFF);
  33. this.buffer[this.offset++] = (num >>> 0 & 0xFF);
  34. return this;
  35. };
  36. //for versions of node requiring 'length' as 3rd argument to buffer.write
  37. var writeString = function (buffer, string, offset, len) {
  38. buffer.write(string, offset, len);
  39. };
  40. //overwrite function for older versions of node
  41. if (Buffer.prototype.write.length === 3) {
  42. writeString = function (buffer, string, offset, len) {
  43. buffer.write(string, offset);
  44. };
  45. }
  46. Writer.prototype.addCString = function (string) {
  47. //just write a 0 for empty or null strings
  48. if (!string) {
  49. this._ensure(1);
  50. } else {
  51. var len = Buffer.byteLength(string);
  52. this._ensure(len + 1); //+1 for null terminator
  53. writeString(this.buffer, string, this.offset, len);
  54. this.offset += len;
  55. }
  56. this.buffer[this.offset++] = 0; // null terminator
  57. return this;
  58. };
  59. Writer.prototype.addChar = function (c) {
  60. this._ensure(1);
  61. writeString(this.buffer, c, this.offset, 1);
  62. this.offset++;
  63. return this;
  64. };
  65. Writer.prototype.addString = function (string) {
  66. string = string || "";
  67. var len = Buffer.byteLength(string);
  68. this._ensure(len);
  69. this.buffer.write(string, this.offset);
  70. this.offset += len;
  71. return this;
  72. };
  73. Writer.prototype.getByteLength = function () {
  74. return this.offset - 5;
  75. };
  76. Writer.prototype.add = function (otherBuffer) {
  77. this._ensure(otherBuffer.length);
  78. otherBuffer.copy(this.buffer, this.offset);
  79. this.offset += otherBuffer.length;
  80. return this;
  81. };
  82. Writer.prototype.clear = function () {
  83. this.offset = 5;
  84. this.headerPosition = 0;
  85. this.lastEnd = 0;
  86. };
  87. //appends a header block to all the written data since the last
  88. //subsequent header or to the beginning if there is only one data block
  89. Writer.prototype.addHeader = function (code, last) {
  90. var origOffset = this.offset;
  91. this.offset = this.headerPosition;
  92. this.buffer[this.offset++] = code;
  93. //length is everything in this packet minus the code
  94. this.addInt32(origOffset - (this.headerPosition + 1));
  95. //set next header position
  96. this.headerPosition = origOffset;
  97. //make space for next header
  98. this.offset = origOffset;
  99. if (!last) {
  100. this._ensure(5);
  101. this.offset += 5;
  102. }
  103. };
  104. Writer.prototype.join = function (code) {
  105. if (code) {
  106. this.addHeader(code, true);
  107. }
  108. return this.buffer.slice(code ? 0 : 5, this.offset);
  109. };
  110. Writer.prototype.flush = function (code) {
  111. var result = this.join(code);
  112. this.clear();
  113. return result;
  114. };