buffer-writer.ts
1 //binary data writer tuned for encoding binary specific to the postgres binary protocol 2 3 export class Writer { 4 private buffer: Buffer 5 private offset: number = 5 6 private headerPosition: number = 0 7 constructor(private size = 256) { 8 this.buffer = Buffer.allocUnsafe(size) 9 } 10 11 private ensure(size: number): void { 12 const remaining = this.buffer.length - this.offset 13 if (remaining < size) { 14 const oldBuffer = this.buffer 15 // exponential growth factor of around ~ 1.5 16 // https://stackoverflow.com/questions/2269063/buffer-growth-strategy 17 const newSize = oldBuffer.length + (oldBuffer.length >> 1) + size 18 this.buffer = Buffer.allocUnsafe(newSize) 19 oldBuffer.copy(this.buffer) 20 } 21 } 22 23 public addInt32(num: number): Writer { 24 this.ensure(4) 25 this.buffer[this.offset++] = (num >>> 24) & 0xff 26 this.buffer[this.offset++] = (num >>> 16) & 0xff 27 this.buffer[this.offset++] = (num >>> 8) & 0xff 28 this.buffer[this.offset++] = (num >>> 0) & 0xff 29 return this 30 } 31 32 public addInt16(num: number): Writer { 33 this.ensure(2) 34 this.buffer[this.offset++] = (num >>> 8) & 0xff 35 this.buffer[this.offset++] = (num >>> 0) & 0xff 36 return this 37 } 38 39 public addCString(string: string): Writer { 40 if (!string) { 41 this.ensure(1) 42 } else { 43 const len = Buffer.byteLength(string) 44 this.ensure(len + 1) // +1 for null terminator 45 this.buffer.write(string, this.offset, 'utf-8') 46 this.offset += len 47 } 48 49 this.buffer[this.offset++] = 0 // null terminator 50 return this 51 } 52 53 public addString(string: string = ''): Writer { 54 const len = Buffer.byteLength(string) 55 this.ensure(len) 56 this.buffer.write(string, this.offset) 57 this.offset += len 58 return this 59 } 60 61 public add(otherBuffer: Buffer): Writer { 62 this.ensure(otherBuffer.length) 63 otherBuffer.copy(this.buffer, this.offset) 64 this.offset += otherBuffer.length 65 return this 66 } 67 68 private join(code?: number): Buffer { 69 if (code) { 70 this.buffer[this.headerPosition] = code 71 //length is everything in this packet minus the code 72 const length = this.offset - (this.headerPosition + 1) 73 this.buffer.writeInt32BE(length, this.headerPosition + 1) 74 } 75 return this.buffer.slice(code ? 0 : 5, this.offset) 76 } 77 78 public flush(code?: number): Buffer { 79 const result = this.join(code) 80 this.offset = 5 81 this.headerPosition = 0 82 this.buffer = Buffer.allocUnsafe(this.size) 83 return result 84 } 85 }