1 | (function() {
|
2 | var CND, _decode, _encode, _invert_buffer, badge, bytecount_date, bytecount_number, bytecount_singular, bytecount_typemarker, debug, grow_rbuffer, rbuffer, rbuffer_max_size, rbuffer_min_size, read_date, read_list, read_nnumber, read_pnumber, read_private, read_singular, read_text, release_extraneous_rbuffer_bytes, rpr, symbol_fallback, tm_date, tm_false, tm_hi, tm_list, tm_lo, tm_ninfinity, tm_nnumber, tm_null, tm_pinfinity, tm_pnumber, tm_private, tm_text, tm_true, warn, write, write_date, write_infinity, write_number, write_private, write_singular, write_text;
|
3 |
|
4 | CND = require('cnd');
|
5 |
|
6 | rpr = CND.rpr;
|
7 |
|
8 | badge = 'HOLLERITH/CODEC';
|
9 |
|
10 | debug = CND.get_logger('debug', badge);
|
11 |
|
12 | warn = CND.get_logger('warn', badge);
|
13 |
|
14 | CND.shim();
|
15 |
|
16 | this['typemarkers'] = {};
|
17 |
|
18 | tm_lo = this['typemarkers']['lo'] = 0x00;
|
19 |
|
20 | tm_null = this['typemarkers']['null'] = 'B'.codePointAt(0);
|
21 |
|
22 | tm_false = this['typemarkers']['false'] = 'C'.codePointAt(0);
|
23 |
|
24 | tm_true = this['typemarkers']['true'] = 'D'.codePointAt(0);
|
25 |
|
26 | tm_list = this['typemarkers']['list'] = 'E'.codePointAt(0);
|
27 |
|
28 | tm_date = this['typemarkers']['date'] = 'G'.codePointAt(0);
|
29 |
|
30 | tm_ninfinity = this['typemarkers']['ninfinity'] = 'J'.codePointAt(0);
|
31 |
|
32 | tm_nnumber = this['typemarkers']['nnumber'] = 'K'.codePointAt(0);
|
33 |
|
34 | tm_pnumber = this['typemarkers']['pnumber'] = 'L'.codePointAt(0);
|
35 |
|
36 | tm_pinfinity = this['typemarkers']['pinfinity'] = 'M'.codePointAt(0);
|
37 |
|
38 | tm_text = this['typemarkers']['text'] = 'T'.codePointAt(0);
|
39 |
|
40 | tm_private = this['typemarkers']['private'] = 'Z'.codePointAt(0);
|
41 |
|
42 | tm_hi = this['typemarkers']['hi'] = 0xff;
|
43 |
|
44 | this['bytecounts'] = {};
|
45 |
|
46 | bytecount_singular = this['bytecounts']['singular'] = 1;
|
47 |
|
48 | bytecount_typemarker = this['bytecounts']['typemarker'] = 1;
|
49 |
|
50 | bytecount_number = this['bytecounts']['number'] = 9;
|
51 |
|
52 | bytecount_date = this['bytecounts']['date'] = bytecount_number + 1;
|
53 |
|
54 | this['sentinels'] = {};
|
55 |
|
56 |
|
57 |
|
58 |
|
59 | this['sentinels']['firstdate'] = new Date(-8640000000000000);
|
60 |
|
61 | this['sentinels']['lastdate'] = new Date(+8640000000000000);
|
62 |
|
63 | this['keys'] = {};
|
64 |
|
65 | this['keys']['lo'] = new Buffer([this['typemarkers']['lo']]);
|
66 |
|
67 | this['keys']['hi'] = new Buffer([this['typemarkers']['hi']]);
|
68 |
|
69 | this['symbols'] = {};
|
70 |
|
71 | symbol_fallback = this['fallback'] = Symbol('fallback');
|
72 |
|
73 | rbuffer_min_size = 1024;
|
74 |
|
75 | rbuffer_max_size = 65536;
|
76 |
|
77 | rbuffer = new Buffer(rbuffer_min_size);
|
78 |
|
79 | grow_rbuffer = function() {
|
80 | var factor, new_result_buffer, new_size;
|
81 | factor = 2;
|
82 | new_size = Math.floor(rbuffer.length * factor + 0.5);
|
83 | new_result_buffer = new Buffer(new_size);
|
84 | rbuffer.copy(new_result_buffer);
|
85 | rbuffer = new_result_buffer;
|
86 | return null;
|
87 | };
|
88 |
|
89 | release_extraneous_rbuffer_bytes = function() {
|
90 | if (rbuffer.length > rbuffer_max_size) {
|
91 | rbuffer = new Buffer(rbuffer_max_size);
|
92 | }
|
93 | return null;
|
94 | };
|
95 |
|
96 | write_singular = function(idx, value) {
|
97 | var typemarker;
|
98 | while (!(rbuffer.length >= idx + bytecount_singular)) {
|
99 | grow_rbuffer();
|
100 | }
|
101 | if (value === null) {
|
102 | typemarker = tm_null;
|
103 | } else if (value === false) {
|
104 | typemarker = tm_false;
|
105 | } else if (value === true) {
|
106 | typemarker = tm_true;
|
107 | } else {
|
108 | throw new Error("unable to encode value of type " + (CND.type_of(value)));
|
109 | }
|
110 | rbuffer[idx] = typemarker;
|
111 | return idx + bytecount_singular;
|
112 | };
|
113 |
|
114 | read_singular = function(buffer, idx) {
|
115 | var typemarker, value;
|
116 | switch (typemarker = buffer[idx]) {
|
117 | case tm_null:
|
118 | value = null;
|
119 | break;
|
120 | case tm_false:
|
121 | value = false;
|
122 | break;
|
123 | case tm_true:
|
124 | value = true;
|
125 | break;
|
126 | default:
|
127 | throw new Error("unable to decode 0x" + (typemarker.toString(16)) + " at index " + idx + " (" + (rpr(buffer)) + ")");
|
128 | }
|
129 | return [idx + bytecount_singular, value];
|
130 | };
|
131 |
|
132 | write_private = function(idx, value, encoder) {
|
133 | var encoded_value, ref, type, wrapped_value;
|
134 | while (!(rbuffer.length >= idx + 3 * bytecount_typemarker)) {
|
135 | grow_rbuffer();
|
136 | }
|
137 | rbuffer[idx] = tm_private;
|
138 | idx += bytecount_typemarker;
|
139 | rbuffer[idx] = tm_list;
|
140 | idx += bytecount_typemarker;
|
141 | type = (ref = value['type']) != null ? ref : 'private';
|
142 | value = value['value'];
|
143 | if (encoder != null) {
|
144 | encoded_value = encoder(type, value, symbol_fallback);
|
145 | if (encoded_value !== symbol_fallback) {
|
146 | value = encoded_value;
|
147 | }
|
148 | }
|
149 | wrapped_value = [type, value];
|
150 | idx = _encode(wrapped_value, idx);
|
151 | rbuffer[idx] = tm_lo;
|
152 | idx += bytecount_typemarker;
|
153 | return idx;
|
154 | };
|
155 |
|
156 | read_private = function(buffer, idx, decoder) {
|
157 | var R, ref, ref1, type, value;
|
158 | idx += bytecount_typemarker;
|
159 | ref = read_list(buffer, idx), idx = ref[0], (ref1 = ref[1], type = ref1[0], value = ref1[1]);
|
160 | if (decoder != null) {
|
161 | R = decoder(type, value, symbol_fallback);
|
162 | if (R === void 0) {
|
163 | throw new Error("encountered illegal value `undefined` when reading private type");
|
164 | }
|
165 | }
|
166 | if (R === symbol_fallback || (decoder == null)) {
|
167 | R = {
|
168 | type: type,
|
169 | value: value
|
170 | };
|
171 | }
|
172 | return [idx, R];
|
173 | };
|
174 |
|
175 | write_number = function(idx, number) {
|
176 | var type;
|
177 | while (!(rbuffer.length >= idx + bytecount_number)) {
|
178 | grow_rbuffer();
|
179 | }
|
180 | if (number < 0) {
|
181 | type = tm_nnumber;
|
182 | number = -number;
|
183 | } else {
|
184 | type = tm_pnumber;
|
185 | }
|
186 | rbuffer[idx] = type;
|
187 | rbuffer.writeDoubleBE(number, idx + 1);
|
188 | if (type === tm_nnumber) {
|
189 | _invert_buffer(rbuffer, idx);
|
190 | }
|
191 | return idx + bytecount_number;
|
192 | };
|
193 |
|
194 | write_infinity = function(idx, number) {
|
195 | while (!(rbuffer.length >= idx + bytecount_singular)) {
|
196 | grow_rbuffer();
|
197 | }
|
198 | rbuffer[idx] = number === -Infinity ? tm_ninfinity : tm_pinfinity;
|
199 | return idx + bytecount_singular;
|
200 | };
|
201 |
|
202 | read_nnumber = function(buffer, idx) {
|
203 | var copy;
|
204 | if (buffer[idx] !== tm_nnumber) {
|
205 | throw new Error("not a negative number at index " + idx);
|
206 | }
|
207 | copy = _invert_buffer(new Buffer(buffer.slice(idx, idx + bytecount_number)), 0);
|
208 | return [idx + bytecount_number, -(copy.readDoubleBE(1))];
|
209 | };
|
210 |
|
211 | read_pnumber = function(buffer, idx) {
|
212 | if (buffer[idx] !== tm_pnumber) {
|
213 | throw new Error("not a positive number at index " + idx);
|
214 | }
|
215 | return [idx + bytecount_number, buffer.readDoubleBE(idx + 1)];
|
216 | };
|
217 |
|
218 | _invert_buffer = function(buffer, idx) {
|
219 | var i, j, ref, ref1;
|
220 | for (i = j = ref = idx + 1, ref1 = idx + 8; ref <= ref1 ? j <= ref1 : j >= ref1; i = ref <= ref1 ? ++j : --j) {
|
221 | buffer[i] = ~buffer[i];
|
222 | }
|
223 | return buffer;
|
224 | };
|
225 |
|
226 | write_date = function(idx, date) {
|
227 | var number;
|
228 | while (!(rbuffer.length >= idx + bytecount_date)) {
|
229 | grow_rbuffer();
|
230 | }
|
231 | number = +date;
|
232 | rbuffer[idx] = tm_date;
|
233 | return write_number(idx + 1, number);
|
234 | };
|
235 |
|
236 | read_date = function(buffer, idx) {
|
237 | var ref, ref1, type, value;
|
238 | if (buffer[idx] !== tm_date) {
|
239 | throw new Error("not a date at index " + idx);
|
240 | }
|
241 | switch (type = buffer[idx + 1]) {
|
242 | case tm_nnumber:
|
243 | ref = read_nnumber(buffer, idx + 1), idx = ref[0], value = ref[1];
|
244 | break;
|
245 | case tm_pnumber:
|
246 | ref1 = read_pnumber(buffer, idx + 1), idx = ref1[0], value = ref1[1];
|
247 | break;
|
248 | default:
|
249 | throw new Error("unknown date type marker 0x" + (type.toString(16)) + " at index " + idx);
|
250 | }
|
251 | return [idx, new Date(value)];
|
252 | };
|
253 |
|
254 | write_text = function(idx, text) {
|
255 | var bytecount_text;
|
256 | text = text.replace(/\x01/g, '\x01\x02');
|
257 | text = text.replace(/\x00/g, '\x01\x01');
|
258 | bytecount_text = (Buffer.byteLength(text, 'utf-8')) + 2;
|
259 | while (!(rbuffer.length >= idx + bytecount_text)) {
|
260 | grow_rbuffer();
|
261 | }
|
262 | rbuffer[idx] = tm_text;
|
263 | rbuffer.write(text, idx + 1);
|
264 | rbuffer[idx + bytecount_text - 1] = tm_lo;
|
265 | return idx + bytecount_text;
|
266 | };
|
267 |
|
268 | read_text = function(buffer, idx) {
|
269 | var R, byte, stop_idx;
|
270 | if (buffer[idx] !== tm_text) {
|
271 | throw new Error("not a text at index " + idx);
|
272 | }
|
273 | stop_idx = idx;
|
274 | while (true) {
|
275 | stop_idx += +1;
|
276 | if ((byte = buffer[stop_idx]) === tm_lo) {
|
277 | break;
|
278 | }
|
279 | if (byte == null) {
|
280 | throw new Error("runaway string at index " + idx);
|
281 | }
|
282 | }
|
283 | R = buffer.toString('utf-8', idx + 1, stop_idx);
|
284 | R = R.replace(/\x01\x01/g, '\x00');
|
285 | R = R.replace(/\x01\x02/g, '\x01');
|
286 | return [stop_idx + 1, R];
|
287 | };
|
288 |
|
289 | read_list = function(buffer, idx) {
|
290 | var R, byte, ref, value;
|
291 | if (buffer[idx] !== tm_list) {
|
292 | throw new Error("not a list at index " + idx);
|
293 | }
|
294 | R = [];
|
295 | idx += +1;
|
296 | while (true) {
|
297 | if ((byte = buffer[idx]) === tm_lo) {
|
298 | break;
|
299 | }
|
300 | ref = _decode(buffer, idx, true), idx = ref[0], value = ref[1];
|
301 | R.push(value[0]);
|
302 | if (byte == null) {
|
303 | throw new Error("runaway list at index " + idx);
|
304 | }
|
305 | }
|
306 | return [idx + 1, R];
|
307 | };
|
308 |
|
309 | write = function(idx, value, encoder) {
|
310 | var type;
|
311 | switch (type = CND.type_of(value)) {
|
312 | case 'text':
|
313 | return write_text(idx, value);
|
314 | case 'number':
|
315 | return write_number(idx, value);
|
316 | case 'jsinfinity':
|
317 | return write_infinity(idx, value);
|
318 | case 'jsdate':
|
319 | return write_date(idx, value);
|
320 | }
|
321 | if (CND.isa_pod(value)) {
|
322 | return write_private(idx, value, encoder);
|
323 | }
|
324 | return write_singular(idx, value);
|
325 | };
|
326 |
|
327 | this.encode = function(key, encoder) {
|
328 | var R, idx, type;
|
329 | rbuffer.fill(0x00);
|
330 | if ((type = CND.type_of(key)) !== 'list') {
|
331 | throw new Error("expected a list, got a " + type);
|
332 | }
|
333 | idx = _encode(key, 0, encoder);
|
334 | R = new Buffer(idx);
|
335 | rbuffer.copy(R, 0, 0, idx);
|
336 | release_extraneous_rbuffer_bytes();
|
337 | return R;
|
338 | };
|
339 |
|
340 | this.encode_plus_hi = function(key, encoder) {
|
341 |
|
342 |
|
343 | var R, idx, type;
|
344 | rbuffer.fill(0x00);
|
345 | if ((type = CND.type_of(key)) !== 'list') {
|
346 | throw new Error("expected a list, got a " + type);
|
347 | }
|
348 | idx = _encode(key, 0, encoder);
|
349 | while (!(rbuffer.length >= idx + 1)) {
|
350 | grow_rbuffer();
|
351 | }
|
352 | rbuffer[idx] = tm_hi;
|
353 | idx += +1;
|
354 | R = new Buffer(idx);
|
355 | rbuffer.copy(R, 0, 0, idx);
|
356 | release_extraneous_rbuffer_bytes();
|
357 | return R;
|
358 | };
|
359 |
|
360 | _encode = function(key, idx, encoder) {
|
361 | var element, element_idx, error, j, k, key_rpr, l, last_element_idx, len, len1, len2, sub_element;
|
362 | last_element_idx = key.length - 1;
|
363 | for (element_idx = j = 0, len = key.length; j < len; element_idx = ++j) {
|
364 | element = key[element_idx];
|
365 | try {
|
366 | if (CND.isa_list(element)) {
|
367 | rbuffer[idx] = tm_list;
|
368 | idx += +1;
|
369 | for (k = 0, len1 = element.length; k < len1; k++) {
|
370 | sub_element = element[k];
|
371 | idx = _encode([sub_element], idx, encoder);
|
372 | }
|
373 | rbuffer[idx] = tm_lo;
|
374 | idx += +1;
|
375 | } else {
|
376 | idx = write(idx, element, encoder);
|
377 | }
|
378 | } catch (_error) {
|
379 | error = _error;
|
380 | key_rpr = [];
|
381 | for (l = 0, len2 = key.length; l < len2; l++) {
|
382 | element = key[l];
|
383 | if (CND.isa_jsbuffer(element)) {
|
384 | key_rpr.push("" + (this.rpr_of_buffer(null, key[2])));
|
385 | } else {
|
386 | key_rpr.push(rpr(element));
|
387 | }
|
388 | }
|
389 | warn("detected problem with key [ " + (rpr(key_rpr.join(', '))) + " ]");
|
390 | throw error;
|
391 | }
|
392 | }
|
393 | return idx;
|
394 | };
|
395 |
|
396 | this.decode = function(buffer, decoder) {
|
397 | return (_decode(buffer, 0, false, decoder))[1];
|
398 | };
|
399 |
|
400 | _decode = function(buffer, idx, single, decoder) {
|
401 | var R, last_idx, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, type, value;
|
402 | R = [];
|
403 | last_idx = buffer.length - 1;
|
404 | while (true) {
|
405 | if (idx > last_idx) {
|
406 | break;
|
407 | }
|
408 | switch (type = buffer[idx]) {
|
409 | case tm_list:
|
410 | ref = read_list(buffer, idx), idx = ref[0], value = ref[1];
|
411 | break;
|
412 | case tm_text:
|
413 | ref1 = read_text(buffer, idx), idx = ref1[0], value = ref1[1];
|
414 | break;
|
415 | case tm_nnumber:
|
416 | ref2 = read_nnumber(buffer, idx), idx = ref2[0], value = ref2[1];
|
417 | break;
|
418 | case tm_ninfinity:
|
419 | ref3 = [idx + 1, -Infinity], idx = ref3[0], value = ref3[1];
|
420 | break;
|
421 | case tm_pnumber:
|
422 | ref4 = read_pnumber(buffer, idx), idx = ref4[0], value = ref4[1];
|
423 | break;
|
424 | case tm_pinfinity:
|
425 | ref5 = [idx + 1, +Infinity], idx = ref5[0], value = ref5[1];
|
426 | break;
|
427 | case tm_date:
|
428 | ref6 = read_date(buffer, idx), idx = ref6[0], value = ref6[1];
|
429 | break;
|
430 | case tm_private:
|
431 | ref7 = read_private(buffer, idx, decoder), idx = ref7[0], value = ref7[1];
|
432 | break;
|
433 | default:
|
434 | ref8 = read_singular(buffer, idx), idx = ref8[0], value = ref8[1];
|
435 | }
|
436 | R.push(value);
|
437 | if (single) {
|
438 | break;
|
439 | }
|
440 | }
|
441 | return [idx, R];
|
442 | };
|
443 |
|
444 | this.encodings = {
|
445 | dbcs2: "⓪①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳㉑㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛\n㉜!"#$%&'()*+,-./0123456789:;<=>?\n@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_\n`abcdefghijklmnopqrstuvwxyz{|}~㉠\n㉝㉞㉟㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿㋐㋑㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜㋝\n㋞㋟㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽\n㋾㊊㊋㊌㊍㊎㊏㊐㊑㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜㊝㊞㊟㊠㊡㊢㊣㊤㊥㊦㊧㊨\n㊩㊪㊫㊬㊭㊮㊯㊰㊀㊁㊂㊃㊄㊅㊆㊇㊈㊉㉈㉉㉊㉋㉌㉍㉎㉏⓵⓶⓷⓸⓹〓",
|
446 | aleph: "БДИЛЦЧШЭЮƆƋƏƐƔƥƧƸψŐőŒœŊŁłЯɔɘɐɕəɞ\n␣!\"#$%&'()*+,-./0123456789:;<=>?\n@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n`abcdefghijklmnopqrstuvwxyz{|}~ω\nΓΔΘΛΞΠΣΦΨΩαβγδεζηθικλμνξπρςστυφχ\nЖ¡¢£¤¥¦§¨©ª«¬Я®¯°±²³´µ¶·¸¹º»¼½¾¿\nÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß\nàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ",
|
447 | rdctn: "∇≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡≡\n␣!\"#$%&'()*+,-./0123456789:;<=>?\n@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_\n`abcdefghijklmnopqrstuvwxyz{|}~≡\n∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃∃\n∃∃¢£¤¥¦§¨©ª«¬Я®¯°±²³´µ¶·¸¹º»¼½¾¿\nÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞß\nàáâãäåæçèéêëìíîïðñò≢≢≢≢≢≢≢≢≢≢≢≢Δ"
|
448 | };
|
449 |
|
450 | this.rpr_of_buffer = function(buffer, encoding) {
|
451 | return (rpr(buffer)) + ' ' + this._encode_buffer(buffer, encoding);
|
452 | };
|
453 |
|
454 | this._encode_buffer = function(buffer, encoding) {
|
455 | var idx;
|
456 | if (encoding == null) {
|
457 | encoding = 'rdctn';
|
458 | }
|
459 |
|
460 |
|
461 | if (!CND.isa_list(encoding)) {
|
462 | encoding = this.encodings[encoding];
|
463 | }
|
464 | return ((function() {
|
465 | var j, ref, results;
|
466 | results = [];
|
467 | for (idx = j = 0, ref = buffer.length; 0 <= ref ? j < ref : j > ref; idx = 0 <= ref ? ++j : --j) {
|
468 | results.push(encoding[buffer[idx]]);
|
469 | }
|
470 | return results;
|
471 | })()).join('');
|
472 | };
|
473 |
|
474 | this._compile_encodings = function() {
|
475 | var chrs_of, encoding, length, name, ref;
|
476 | chrs_of = function(text) {
|
477 | var chr;
|
478 | text = text.split(/([\ud800-\udbff].|.)/);
|
479 | return (function() {
|
480 | var j, len, results;
|
481 | results = [];
|
482 | for (j = 0, len = text.length; j < len; j++) {
|
483 | chr = text[j];
|
484 | if (chr !== '') {
|
485 | results.push(chr);
|
486 | }
|
487 | }
|
488 | return results;
|
489 | })();
|
490 | };
|
491 | ref = this.encodings;
|
492 | for (name in ref) {
|
493 | encoding = ref[name];
|
494 | encoding = chrs_of(encoding.replace(/\n+/g, ''));
|
495 | if ((length = encoding.length) !== 256) {
|
496 | throw new Error("expected 256 characters, found " + length + " in encoding " + (rpr(name)));
|
497 | }
|
498 | this.encodings[name] = encoding;
|
499 | }
|
500 | return null;
|
501 | };
|
502 |
|
503 | this._compile_encodings();
|
504 |
|
505 | }).call(this);
|
506 |
|
507 |
|
\ | No newline at end of file |