|
| 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.alloc(size) |
| 9 | + } |
| 10 | + |
| 11 | + private ensure(size: number): void { |
| 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 | + |
| 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 | + |
| 40 | + public addCString(string: string): Writer { |
| 41 | + if (!string) { |
| 42 | + this.ensure(1); |
| 43 | + } else { |
| 44 | + var len = Buffer.byteLength(string); |
| 45 | + this.ensure(len + 1); // +1 for null terminator |
| 46 | + this.buffer.write(string, this.offset, 'utf-8') |
| 47 | + this.offset += len; |
| 48 | + } |
| 49 | + |
| 50 | + this.buffer[this.offset++] = 0; // null terminator |
| 51 | + return this; |
| 52 | + } |
| 53 | + |
| 54 | + public addString(string: string = ""): Writer { |
| 55 | + var len = Buffer.byteLength(string); |
| 56 | + this.ensure(len); |
| 57 | + this.buffer.write(string, this.offset); |
| 58 | + this.offset += len; |
| 59 | + return this; |
| 60 | + } |
| 61 | + |
| 62 | + public add(otherBuffer: Buffer): Writer { |
| 63 | + this.ensure(otherBuffer.length); |
| 64 | + otherBuffer.copy(this.buffer, this.offset); |
| 65 | + this.offset += otherBuffer.length; |
| 66 | + return this; |
| 67 | + } |
| 68 | + |
| 69 | + private join(code?: number): Buffer { |
| 70 | + if (code) { |
| 71 | + this.buffer[this.headerPosition] = code; |
| 72 | + //length is everything in this packet minus the code |
| 73 | + const length = this.offset - (this.headerPosition + 1) |
| 74 | + this.buffer.writeInt32BE(length, this.headerPosition + 1) |
| 75 | + } |
| 76 | + return this.buffer.slice(code ? 0 : 5, this.offset); |
| 77 | + } |
| 78 | + |
| 79 | + public flush(code?: number): Buffer { |
| 80 | + var result = this.join(code); |
| 81 | + this.offset = 5; |
| 82 | + this.headerPosition = 0; |
| 83 | + this.buffer = Buffer.allocUnsafe(this.size) |
| 84 | + return result; |
| 85 | + } |
| 86 | +} |
| 87 | + |
0 commit comments