Skip to content

Commit 2d9b674

Browse files
committed
Rewrite bits.js to use builder and consumer objects instead of raw strings. Now we don't have to clobber the String object.
1 parent af33862 commit 2d9b674

File tree

1 file changed

+126
-89
lines changed

1 file changed

+126
-89
lines changed

postgres-js/bits.js

Lines changed: 126 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -4,94 +4,131 @@
44
// streams which are encoded as javascript strings
55
// that only use the first 8 bits of each character.
66

7-
// Quick alias to shorten call time and to shorten code
8-
var chr = String.fromCharCode;
9-
10-
// Encode number as 32 bit 2s compliment
11-
String.prototype.add_int32 = function (number) {
12-
var a, b, c, d, unsigned;
13-
unsigned = (number < 0) ? (number + 0x100000000) : number;
14-
a = Math.floor(unsigned / 0xffffff);
15-
unsigned &= 0xffffff;
16-
b = Math.floor(unsigned / 0xffff);
17-
unsigned &= 0xffff;
18-
c = Math.floor(unsigned / 0xff);
19-
unsigned &= 0xff;
20-
d = Math.floor(unsigned);
21-
return this + chr(a) + chr(b) + chr(c) + chr(d);
22-
};
23-
24-
// Encode number as 16 bit 2s compliment
25-
String.prototype.add_int16 = function (number) {
26-
var a, b, unsigned;
27-
unsigned = (number < 0) ? (number + 0x10000) : number;
28-
a = Math.floor(unsigned / 0xff);
29-
unsigned &= 0xff;
30-
b = Math.floor(unsigned);
31-
return this + chr(a) + chr(b);
32-
};
33-
34-
// Encode string without null terminator
35-
String.prototype.add_raw_string = function (text) {
36-
return this + text;
37-
};
38-
39-
// Encode text as null terminated string
40-
String.prototype.add_cstring = function (text) {
41-
return this + text + "\0";
42-
};
43-
44-
// Encode as a null terminated array of cstrings
45-
String.prototype.add_multi_cstring = function (fields) {
46-
return this + fields.join("\0") + "\0\0";
47-
};
48-
49-
// Convert 4 characters to signed 32 bit integer
50-
String.prototype.parse_int32 = function () {
51-
var unsigned = this.charCodeAt(0) * 0x1000000 + this.charCodeAt(1) * 0x10000 + this.charCodeAt(2) * 0x100 + this.charCodeAt(3);
52-
return [4, (unsigned & 0x80000000) ? (unsigned - 0x100000000) : unsigned];
53-
};
54-
55-
// Convert 2 bytes to signed 16 bit integer
56-
String.prototype.parse_int16 = function () {
57-
var unsigned = this.charCodeAt(0) * 0x100 + this.charCodeAt(1);
58-
return [2, (unsigned & 0x8000) ? (unsigned - 0x10000) : unsigned];
59-
};
60-
61-
// Grab number of bytes as a string
62-
String.prototype.parse_raw_string = function (len) {
63-
return [len, this.substr(0, len)];
64-
};
65-
66-
// Grab a null terminated string from the this
67-
String.prototype.parse_cstring = function () {
68-
var pos = this.indexOf("\0");
69-
return [pos + 1, this.substr(0, pos)];
70-
};
71-
72-
// Grab a null terminated array of null terminated strings
73-
String.prototype.parse_multi_cstring = function () {
74-
var pos = this.indexOf("\0\0");
75-
return [pos + 2, this.substr(0, pos).split("\0")];
76-
};
77-
78-
// Takes any number of commands to tell how to parse the binary input.
79-
String.prototype.parse = function () {
80-
var pos, self, data;
81-
pos = 0;
82-
self = this;
83-
data = Array.prototype.map.call(arguments, function (command) {
84-
var args, pair;
85-
if (typeof command === 'string') {
86-
args = [];
87-
} else {
88-
args = command.slice(1);
89-
command = command[0];
7+
// exports.Encoder - A binary string builder object.
8+
(function () {
9+
10+
var chr, proto;
11+
12+
exports.Encoder = function () {
13+
this.data = "";
14+
};
15+
16+
chr = String.fromCharCode;
17+
proto = exports.Encoder.prototype;
18+
19+
// Factor out the encode so it can be shared by add_header and push_int32
20+
function encode_int32(number) {
21+
var a, b, c, d, unsigned;
22+
unsigned = (number < 0) ? (number + 0x100000000) : number;
23+
a = Math.floor(unsigned / 0xffffff);
24+
unsigned &= 0xffffff;
25+
b = Math.floor(unsigned / 0xffff);
26+
unsigned &= 0xffff;
27+
c = Math.floor(unsigned / 0xff);
28+
unsigned &= 0xff;
29+
d = Math.floor(unsigned);
30+
return chr(a) + chr(b) + chr(c) + chr(d);
31+
}
32+
33+
// Add a postgres header to the binary string
34+
proto.add_header = function (code) {
35+
if (code === undefined) {
36+
code = "";
9037
}
91-
pair = String.prototype["parse_" + command].apply(self.substr(pos), args);
92-
pos += pair[0];
93-
return pair[1];
94-
});
95-
return [pos, data];
96-
};
38+
this.data = code + encode_int32(this.data.length + 4) + this.data;
39+
return this;
40+
};
41+
42+
// Encode number as 32 bit 2s compliment
43+
proto.push_int32 = function (number) {
44+
this.data += encode_int32(number);
45+
return this;
46+
};
47+
48+
// Encode number as 16 bit 2s compliment
49+
proto.push_int16 = function (number) {
50+
var a, b, unsigned;
51+
unsigned = (number < 0) ? (number + 0x10000) : number;
52+
a = Math.floor(unsigned / 0xff);
53+
unsigned &= 0xff;
54+
b = Math.floor(unsigned);
55+
this.data += chr(a) + chr(b);
56+
return this;
57+
};
58+
59+
// Encode string without null terminator
60+
proto.push_raw_string = function (text) {
61+
this.data += text;
62+
return this;
63+
};
64+
65+
// Encode text as null terminated string
66+
proto.push_cstring = function (text) {
67+
this.data += text + "\0";
68+
return this;
69+
};
70+
71+
// Encode as a null terminated array of cstrings
72+
proto.push_multi_cstring = function (fields) {
73+
this.data += fields.join("\0") + "\0\0";
74+
return this;
75+
};
76+
77+
}());
78+
79+
// exports.Decoder - A binary string consumer object.
80+
// TODO: Convert to use a moving pointer instead of creating a new substring
81+
// each iteration. This will help performance a bit on parsing.
82+
(function () {
83+
84+
var proto;
85+
86+
exports.Decoder = function (data) {
87+
this.data = data;
88+
};
89+
90+
proto = exports.Decoder.prototype;
91+
92+
// Convert 4 characters to signed 32 bit integer
93+
proto.shift_int32 = function () {
94+
var unsigned = this.data.charCodeAt(0) * 0x1000000 + this.data.charCodeAt(1) * 0x10000 + this.data.charCodeAt(2) * 0x100 + this.data.charCodeAt(3);
95+
this.data = this.data.substr(4);
96+
return (unsigned & 0x80000000) ? (unsigned - 0x100000000) : unsigned;
97+
};
98+
99+
// Convert 2 bytes to signed 16 bit integer
100+
proto.shift_int16 = function () {
101+
var unsigned = this.data.charCodeAt(0) * 0x100 + this.data.charCodeAt(1);
102+
this.data = this.data.substr(2);
103+
return (unsigned & 0x8000) ? (unsigned - 0x10000) : unsigned;
104+
};
105+
106+
// Grab number of bytes as a string
107+
proto.shift_raw_string = function (len) {
108+
var string = this.data.substr(0, len);
109+
this.data = this.data.substr(len);
110+
return string;
111+
};
112+
113+
// Grab a null terminated string
114+
proto.shift_cstring = function () {
115+
var pos, string;
116+
pos = this.indexOf("\0");
117+
string = this.data.substr(0, pos);
118+
this.data = this.data.substr(pos + 1);
119+
return string;
120+
};
121+
122+
// Grab a null terminated array of null terminated strings
123+
proto.shift_multi_cstring = function () {
124+
var pos, string;
125+
pos = this.data.indexOf("\0\0");
126+
string = this.data.substr(0, pos).split("\0");
127+
this.data = this.data.substr(pos + 1);
128+
return string;
129+
};
130+
131+
132+
}());
133+
97134

0 commit comments

Comments
 (0)