1 | "use strict";
|
2 | var Buffer = require("safer-buffer").Buffer;
|
3 |
|
4 |
|
5 |
|
6 | module.exports = {
|
7 |
|
8 | utf8: { type: "_internal", bomAware: true},
|
9 | cesu8: { type: "_internal", bomAware: true},
|
10 | unicode11utf8: "utf8",
|
11 |
|
12 | ucs2: { type: "_internal", bomAware: true},
|
13 | utf16le: "ucs2",
|
14 |
|
15 | binary: { type: "_internal" },
|
16 | base64: { type: "_internal" },
|
17 | hex: { type: "_internal" },
|
18 |
|
19 |
|
20 | _internal: InternalCodec,
|
21 | };
|
22 |
|
23 |
|
24 |
|
25 | function InternalCodec(codecOptions, iconv) {
|
26 | this.enc = codecOptions.encodingName;
|
27 | this.bomAware = codecOptions.bomAware;
|
28 |
|
29 | if (this.enc === "base64")
|
30 | this.encoder = InternalEncoderBase64;
|
31 | else if (this.enc === "cesu8") {
|
32 | this.enc = "utf8";
|
33 | this.encoder = InternalEncoderCesu8;
|
34 |
|
35 |
|
36 | if (Buffer.from('eda0bdedb2a9', 'hex').toString() !== '💩') {
|
37 | this.decoder = InternalDecoderCesu8;
|
38 | this.defaultCharUnicode = iconv.defaultCharUnicode;
|
39 | }
|
40 | }
|
41 | }
|
42 |
|
43 | InternalCodec.prototype.encoder = InternalEncoder;
|
44 | InternalCodec.prototype.decoder = InternalDecoder;
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | var StringDecoder = require('string_decoder').StringDecoder;
|
50 |
|
51 | if (!StringDecoder.prototype.end)
|
52 | StringDecoder.prototype.end = function() {};
|
53 |
|
54 |
|
55 | function InternalDecoder(options, codec) {
|
56 | this.decoder = new StringDecoder(codec.enc);
|
57 | }
|
58 |
|
59 | InternalDecoder.prototype.write = function(buf) {
|
60 | if (!Buffer.isBuffer(buf)) {
|
61 | buf = Buffer.from(buf);
|
62 | }
|
63 |
|
64 | return this.decoder.write(buf);
|
65 | }
|
66 |
|
67 | InternalDecoder.prototype.end = function() {
|
68 | return this.decoder.end();
|
69 | }
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 | function InternalEncoder(options, codec) {
|
76 | this.enc = codec.enc;
|
77 | }
|
78 |
|
79 | InternalEncoder.prototype.write = function(str) {
|
80 | return Buffer.from(str, this.enc);
|
81 | }
|
82 |
|
83 | InternalEncoder.prototype.end = function() {
|
84 | }
|
85 |
|
86 |
|
87 |
|
88 |
|
89 |
|
90 | function InternalEncoderBase64(options, codec) {
|
91 | this.prevStr = '';
|
92 | }
|
93 |
|
94 | InternalEncoderBase64.prototype.write = function(str) {
|
95 | str = this.prevStr + str;
|
96 | var completeQuads = str.length - (str.length % 4);
|
97 | this.prevStr = str.slice(completeQuads);
|
98 | str = str.slice(0, completeQuads);
|
99 |
|
100 | return Buffer.from(str, "base64");
|
101 | }
|
102 |
|
103 | InternalEncoderBase64.prototype.end = function() {
|
104 | return Buffer.from(this.prevStr, "base64");
|
105 | }
|
106 |
|
107 |
|
108 |
|
109 |
|
110 |
|
111 | function InternalEncoderCesu8(options, codec) {
|
112 | }
|
113 |
|
114 | InternalEncoderCesu8.prototype.write = function(str) {
|
115 | var buf = Buffer.alloc(str.length * 3), bufIdx = 0;
|
116 | for (var i = 0; i < str.length; i++) {
|
117 | var charCode = str.charCodeAt(i);
|
118 |
|
119 |
|
120 | if (charCode < 0x80)
|
121 | buf[bufIdx++] = charCode;
|
122 | else if (charCode < 0x800) {
|
123 | buf[bufIdx++] = 0xC0 + (charCode >>> 6);
|
124 | buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
125 | }
|
126 | else {
|
127 | buf[bufIdx++] = 0xE0 + (charCode >>> 12);
|
128 | buf[bufIdx++] = 0x80 + ((charCode >>> 6) & 0x3f);
|
129 | buf[bufIdx++] = 0x80 + (charCode & 0x3f);
|
130 | }
|
131 | }
|
132 | return buf.slice(0, bufIdx);
|
133 | }
|
134 |
|
135 | InternalEncoderCesu8.prototype.end = function() {
|
136 | }
|
137 |
|
138 |
|
139 |
|
140 |
|
141 | function InternalDecoderCesu8(options, codec) {
|
142 | this.acc = 0;
|
143 | this.contBytes = 0;
|
144 | this.accBytes = 0;
|
145 | this.defaultCharUnicode = codec.defaultCharUnicode;
|
146 | }
|
147 |
|
148 | InternalDecoderCesu8.prototype.write = function(buf) {
|
149 | var acc = this.acc, contBytes = this.contBytes, accBytes = this.accBytes,
|
150 | res = '';
|
151 | for (var i = 0; i < buf.length; i++) {
|
152 | var curByte = buf[i];
|
153 | if ((curByte & 0xC0) !== 0x80) {
|
154 | if (contBytes > 0) {
|
155 | res += this.defaultCharUnicode;
|
156 | contBytes = 0;
|
157 | }
|
158 |
|
159 | if (curByte < 0x80) {
|
160 | res += String.fromCharCode(curByte);
|
161 | } else if (curByte < 0xE0) {
|
162 | acc = curByte & 0x1F;
|
163 | contBytes = 1; accBytes = 1;
|
164 | } else if (curByte < 0xF0) {
|
165 | acc = curByte & 0x0F;
|
166 | contBytes = 2; accBytes = 1;
|
167 | } else {
|
168 | res += this.defaultCharUnicode;
|
169 | }
|
170 | } else {
|
171 | if (contBytes > 0) {
|
172 | acc = (acc << 6) | (curByte & 0x3f);
|
173 | contBytes--; accBytes++;
|
174 | if (contBytes === 0) {
|
175 |
|
176 | if (accBytes === 2 && acc < 0x80 && acc > 0)
|
177 | res += this.defaultCharUnicode;
|
178 | else if (accBytes === 3 && acc < 0x800)
|
179 | res += this.defaultCharUnicode;
|
180 | else
|
181 |
|
182 | res += String.fromCharCode(acc);
|
183 | }
|
184 | } else {
|
185 | res += this.defaultCharUnicode;
|
186 | }
|
187 | }
|
188 | }
|
189 | this.acc = acc; this.contBytes = contBytes; this.accBytes = accBytes;
|
190 | return res;
|
191 | }
|
192 |
|
193 | InternalDecoderCesu8.prototype.end = function() {
|
194 | var res = 0;
|
195 | if (this.contBytes > 0)
|
196 | res += this.defaultCharUnicode;
|
197 | return res;
|
198 | }
|