Initial commit for OpenECOMP SDN-C OA&M
[sdnc/oam.git] / dgbuilder / dgeflows / node_modules / body-parser / node_modules / iconv-lite / encodings / utf7.js
1
2 // UTF-7 codec, according to https://tools.ietf.org/html/rfc2152
3 // Below is UTF-7-IMAP codec, according to http://tools.ietf.org/html/rfc3501#section-5.1.3
4
5 exports.utf7 = function(options) {
6     return {
7         encoder: function utf7Encoder() {
8             return {
9                 write: utf7EncoderWrite,
10                 end: function() {},
11
12                 iconv: options.iconv,
13             };
14         },
15         decoder: function utf7Decoder() {
16             return {
17                 write: utf7DecoderWrite,
18                 end: utf7DecoderEnd,
19
20                 iconv: options.iconv,
21                 inBase64: false,
22                 base64Accum: '',
23             };
24         },
25     };
26 };
27
28
29 var nonDirectChars = /[^A-Za-z0-9'\(\),-\.\/:\? \n\r\t]+/g;
30
31 // Direct: \n, \r, \t, 0x20, 0x27-0x29, (0x2B), 0x2C-0x3A, 0x3F, 0x41-0x5A, 0x61-0x7A
32
33 function utf7EncoderWrite(str) {
34     // Naive implementation.
35     // Non-direct chars are encoded as "+<base64>-"; single "+" char is encoded as "+-".
36     return new Buffer(str.replace(nonDirectChars, function(chunk) {
37         return "+" + (chunk === '+' ? '' : 
38             this.iconv.encode(chunk, 'utf16-be').toString('base64').replace(/=+$/, '')) 
39             + "-";
40     }.bind(this)));
41 }
42
43
44 var base64Regex = /[A-Za-z0-9\/+]/;
45 var base64Chars = [];
46 for (var i = 0; i < 256; i++)
47     base64Chars[i] = base64Regex.test(String.fromCharCode(i));
48
49 var plusChar = '+'.charCodeAt(0), 
50     minusChar = '-'.charCodeAt(0),
51     andChar = '&'.charCodeAt(0);
52
53 function utf7DecoderWrite(buf) {
54     var res = "", lastI = 0,
55         inBase64 = this.inBase64,
56         base64Accum = this.base64Accum;
57
58     // The decoder is more involved as we must handle chunks in stream.
59
60     for (var i = 0; i < buf.length; i++) {
61         if (!inBase64) { // We're in direct mode.
62             // Write direct chars until '+'
63             if (buf[i] == plusChar) {
64                 res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars.
65                 lastI = i+1;
66                 inBase64 = true;
67             }
68         } else { // We decode base64.
69             if (!base64Chars[buf[i]]) { // Base64 ended.
70                 if (i == lastI && buf[i] == minusChar) {// "+-" -> "+"
71                     res += "+";
72                 } else {
73                     var b64str = base64Accum + buf.slice(lastI, i).toString();
74                     res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
75                 }
76
77                 if (buf[i] != minusChar) // Minus is absorbed after base64.
78                     i--;
79
80                 lastI = i+1;
81                 inBase64 = false;
82                 base64Accum = '';
83             }
84         }
85     }
86
87     if (!inBase64) {
88         res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
89     } else {
90         var b64str = base64Accum + buf.slice(lastI).toString();
91
92         var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
93         base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.
94         b64str = b64str.slice(0, canBeDecoded);
95
96         res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
97     }
98
99     this.inBase64 = inBase64;
100     this.base64Accum = base64Accum;
101
102     return res;
103 }
104
105 function utf7DecoderEnd() {
106     var res = "";
107     if (this.inBase64 && this.base64Accum.length > 0)
108         res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), "utf16-be");
109
110     this.inBase64 = false;
111     this.base64Accum = '';
112     return res;
113 }
114
115
116 // UTF-7-IMAP codec.
117 // RFC3501 Sec. 5.1.3 Modified UTF-7 (http://tools.ietf.org/html/rfc3501#section-5.1.3)
118 // Differences:
119 //  * Base64 part is started by "&" instead of "+"
120 //  * Direct characters are 0x20-0x7E, except "&" (0x26)
121 //  * In Base64, "," is used instead of "/"
122 //  * Base64 must not be used to represent direct characters.
123 //  * No implicit shift back from Base64 (should always end with '-')
124 //  * String must end in non-shifted position.
125 //  * "-&" while in base64 is not allowed.
126
127
128 exports.utf7imap = function(options) {
129     return {
130         encoder: function utf7ImapEncoder() {
131             return {
132                 write: utf7ImapEncoderWrite,
133                 end: utf7ImapEncoderEnd,
134
135                 iconv: options.iconv,
136                 inBase64: false,
137                 base64Accum: new Buffer(6),
138                 base64AccumIdx: 0,
139             };
140         },
141         decoder: function utf7ImapDecoder() {
142             return {
143                 write: utf7ImapDecoderWrite,
144                 end: utf7ImapDecoderEnd,
145
146                 iconv: options.iconv,
147                 inBase64: false,
148                 base64Accum: '',
149             };
150         },
151     };
152 };
153
154
155 function utf7ImapEncoderWrite(str) {
156     var inBase64 = this.inBase64,
157         base64Accum = this.base64Accum,
158         base64AccumIdx = this.base64AccumIdx,
159         buf = new Buffer(str.length*5 + 10), bufIdx = 0;
160
161     for (var i = 0; i < str.length; i++) {
162         var uChar = str.charCodeAt(i);
163         if (0x20 <= uChar && uChar <= 0x7E) { // Direct character or '&'.
164             if (inBase64) {
165                 if (base64AccumIdx > 0) {
166                     bufIdx += buf.write(base64Accum.slice(0, base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx);
167                     base64AccumIdx = 0;
168                 }
169
170                 buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.
171                 inBase64 = false;
172             }
173
174             if (!inBase64) {
175                 buf[bufIdx++] = uChar; // Write direct character
176
177                 if (uChar === andChar)  // Ampersand -> '&-'
178                     buf[bufIdx++] = minusChar;
179             }
180
181         } else { // Non-direct character
182             if (!inBase64) {
183                 buf[bufIdx++] = andChar; // Write '&', then go to base64 mode.
184                 inBase64 = true;
185             }
186             if (inBase64) {
187                 base64Accum[base64AccumIdx++] = uChar >> 8;
188                 base64Accum[base64AccumIdx++] = uChar & 0xFF;
189
190                 if (base64AccumIdx == base64Accum.length) {
191                     bufIdx += buf.write(base64Accum.toString('base64').replace(/\//g, ','), bufIdx);
192                     base64AccumIdx = 0;
193                 }
194             }
195         }
196     }
197
198     this.inBase64 = inBase64;
199     this.base64AccumIdx = base64AccumIdx;
200
201     return buf.slice(0, bufIdx);
202 }
203
204 function utf7ImapEncoderEnd() {
205     var buf = new Buffer(10), bufIdx = 0;
206     if (this.inBase64) {
207         if (this.base64AccumIdx > 0) {
208             bufIdx += buf.write(this.base64Accum.slice(0, this.base64AccumIdx).toString('base64').replace(/\//g, ',').replace(/=+$/, ''), bufIdx);
209             this.base64AccumIdx = 0;
210         }
211
212         buf[bufIdx++] = minusChar; // Write '-', then go to direct mode.
213         this.inBase64 = false;
214     }
215
216     return buf.slice(0, bufIdx);
217 }
218
219
220 var base64IMAPChars = base64Chars.slice();
221 base64IMAPChars[','.charCodeAt(0)] = true;
222
223 function utf7ImapDecoderWrite(buf) {
224     var res = "", lastI = 0,
225         inBase64 = this.inBase64,
226         base64Accum = this.base64Accum;
227
228     // The decoder is more involved as we must handle chunks in stream.
229     // It is forgiving, closer to standard UTF-7 (for example, '-' is optional at the end).
230
231     for (var i = 0; i < buf.length; i++) {
232         if (!inBase64) { // We're in direct mode.
233             // Write direct chars until '&'
234             if (buf[i] == andChar) {
235                 res += this.iconv.decode(buf.slice(lastI, i), "ascii"); // Write direct chars.
236                 lastI = i+1;
237                 inBase64 = true;
238             }
239         } else { // We decode base64.
240             if (!base64IMAPChars[buf[i]]) { // Base64 ended.
241                 if (i == lastI && buf[i] == minusChar) { // "&-" -> "&"
242                     res += "&";
243                 } else {
244                     var b64str = base64Accum + buf.slice(lastI, i).toString().replace(/,/g, '/');
245                     res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
246                 }
247
248                 if (buf[i] != minusChar) // Minus may be absorbed after base64.
249                     i--;
250
251                 lastI = i+1;
252                 inBase64 = false;
253                 base64Accum = '';
254             }
255         }
256     }
257
258     if (!inBase64) {
259         res += this.iconv.decode(buf.slice(lastI), "ascii"); // Write direct chars.
260     } else {
261         var b64str = base64Accum + buf.slice(lastI).toString().replace(/,/g, '/');
262
263         var canBeDecoded = b64str.length - (b64str.length % 8); // Minimal chunk: 2 quads -> 2x3 bytes -> 3 chars.
264         base64Accum = b64str.slice(canBeDecoded); // The rest will be decoded in future.
265         b64str = b64str.slice(0, canBeDecoded);
266
267         res += this.iconv.decode(new Buffer(b64str, 'base64'), "utf16-be");
268     }
269
270     this.inBase64 = inBase64;
271     this.base64Accum = base64Accum;
272
273     return res;
274 }
275
276 function utf7ImapDecoderEnd() {
277     var res = "";
278     if (this.inBase64 && this.base64Accum.length > 0)
279         res = this.iconv.decode(new Buffer(this.base64Accum, 'base64'), "utf16-be");
280
281     this.inBase64 = false;
282     this.base64Accum = '';
283     return res;
284 }
285
286