1 /**
  2  * @namespace Encoding functions
  3  * @author Anonymized
  4  * @description
  5  * <p>Support for ASCII, UTF-8, Base64 and Hex encoding.</p>
  6  * <p>DJS is simply not good at encoding, because it lacks the
  7  * built-in functions to get the character code at a given offset
  8  * from a string (charCodeAt), and its inverse, String.fromCharCode.</p>
  9  *
 10  * <p>This means we have to use a literal object whose field names are
 11  * ASCII characters and values are the associated codes, and a string
 12  * containing every character sorted by code for the inverse operation.</p>
 13  *
 14  * <p>For UTF-8, such a table would be too large and instead, we use
 15  * binary search on the string containing all UTF-8 characters,
 16  * using the built in lexicographic order of JavaScript.
 17  * Since the complete UTF-8 alphabet is itself 200KB, it is loaded
 18  * from its own file, utf8.js. Loading this file is optional: without
 19  * it every non-ASCII character is treated like the null byte.</p>
 20  */
 21  var encoding =
 22  {
 23 /** Hex alphabet. */
 24   hex: "0123456789abcdef",
 25 
 26 /** UTF-8 alphabet. Initially contains the null byte, actual value is in utf8.js */
 27   utf8: "\x00",
 28 
 29 /** The ASCII alphabet, can be used directly */
 30   ascii: "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\x7f\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
 31 
 32 /** ASCII code table. Has its own dynamic accessor. */
 33   ascii_table: {"0":48,"1":49,"2":50,"3":51,"4":52,"5":53,"6":54,"7":55,"8":56,"9":57,"\x00":0,"\x01":1,"\x02":2,"\x03":3,"\x04":4,"\x05":5,"\x06":6,"\x07":7,"\b":8,"\t":9,"\n":10,"\x0b":11,"\f":12,"\r":13,"\x0e":14,"\x0f":15,"\x10":16,"\x11":17,"\x12":18,"\x13":19,"\x14":20,"\x15":21,"\x16":22,"\x17":23,"\x18":24,"\x19":25,"\x1a":26,"\x1b":27,"\x1c":28,"\x1d":29,"\x1e":30,"\x1f":31," ":32,"!":33,'"':34,"#":35,"$":36,"%":37,"&":38,"'":39,"(":40,")":41,"*":42,"+":43,",":44,"-":45,".":46,"/":47,":":58,";":59,"<":60,"=":61,">":62,"?":63,"@":64,"A":65,"B":66,"C":67,"D":68,"E":69,"F":70,"G":71,"H":72,"I":73,"J":74,"K":75,"L":76,"M":77,"N":78,"O":79,"P":80,"Q":81,"R":82,"S":83,"T":84,"U":85,"V":86,"W":87,"X":88,"Y":89,"Z":90,"[":91,"\\":92,"]":93,"^":94,"_":95,"`":96,"a":97,"b":98,"c":99,"d":100,"e":101,"f":102,"g":103,"h":104,"i":105,"j":106,"k":107,"l":108,"m":109,"n":110,"o":111,"p":112,"q":113,"r":114,"s":115,"t":116,"u":117,"v":118,"w":119,"x":120,"y":121,"z":122,"{":123,"|":124,"}":125,"~":126,"\x7f":127,"\x80":128,"\x81":129,"\x82":130,"\x83":131,"\x84":132,"\x85":133,"\x86":134,"\x87":135,"\x88":136,"\x89":137,"\x8a":138,"\x8b":139,"\x8c":140,"\x8d":141,"\x8e":142,"\x8f":143,"\x90":144,"\x91":145,"\x92":146,"\x93":147,"\x94":148,"\x95":149,"\x96":150,"\x97":151,"\x98":152,"\x99":153,"\x9a":154,"\x9b":155,"\x9c":156,"\x9d":157,"\x9e":158,"\x9f":159,"\xa0":160,"\xa1":161,"\xa2":162,"\xa3":163,"\xa4":164,"\xa5":165,"\xa6":166,"\xa7":167,"\xa8":168,"\xa9":169,"\xaa":170,"\xab":171,"\xac":172,"\xad":173,"\xae":174,"\xaf":175,"\xb0":176,"\xb1":177,"\xb2":178,"\xb3":179,"\xb4":180,"\xb5":181,"\xb6":182,"\xb7":183,"\xb8":184,"\xb9":185,"\xba":186,"\xbb":187,"\xbc":188,"\xbd":189,"\xbe":190,"\xbf":191,"\xc0":192,"\xc1":193,"\xc2":194,"\xc3":195,"\xc4":196,"\xc5":197,"\xc6":198,"\xc7":199,"\xc8":200,"\xc9":201,"\xca":202,"\xcb":203,"\xcc":204,"\xcd":205,"\xce":206,"\xcf":207,"\xd0":208,"\xd1":209,"\xd2":210,"\xd3":211,"\xd4":212,"\xd5":213,"\xd6":214,"\xd7":215,"\xd8":216,"\xd9":217,"\xda":218,"\xdb":219,"\xdc":220,"\xdd":221,"\xde":222,"\xdf":223,"\xe0":224,"\xe1":225,"\xe2":226,"\xe3":227,"\xe4":228,"\xe5":229,"\xe6":230,"\xe7":231,"\xe8":232,"\xe9":233,"\xea":234,"\xeb":235,"\xec":236,"\xed":237,"\xee":238,"\xef":239,"\xf0":240,"\xf1":241,"\xf2":242,"\xf3":243,"\xf4":244,"\xf5":245,"\xf6":246,"\xf7":247,"\xf8":248,"\xf9":249,"\xfa":250,"\xfb":251,"\xfc":252,"\xfd":253,"\xfe":254,"\xff":255},
 34 
 35 /** Base64 alphabet. Is missing the last two characters to support URL style */
 36   base64: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
 37 
 38 /** Binary search of a character inside a sorted string.
 39   * @param {string} char character to search
 40   * @param {string} alphabet string whose characters are sorted in lexicographic order
 41   * @returns {number} the position where char occurs in alphabet, or 0 if not found.
 42   */
 43   _searchCharTable: function(a, table)
 44   {
 45    var a = a+'', table = table+'', min = 0,
 46        max=table.length, m = 0, b = "";
 47    while(m != (m = (min+max)>>1))
 48    {
 49     b = table[(m>>>0)%table.length];
 50     if(a == b) return m;
 51     if(a > b) min = m; else max = m;
 52    } 
 53    return 0;
 54   },
 55 
 56 /** Hex representation of a byte.
 57   * @param {number} input byte
 58   * @returns {string} hex representation of the input, has always length 2.
 59   */
 60   b2h: function(c)
 61   {
 62    var t = this.hex+'',
 63        chr = function(i){return t[(i>>>0)%t.length]};
 64    return chr((c>>4)&15)+chr(c&15);
 65   },
 66 
 67 /** The code of a character in the base64 alphabet. Accept +- or /_, fallback is 0.
 68   * @param {string} input base64 character
 69   * @returns {number} base64 code from 0 to 63
 70   */
 71   b64c: function(s)
 72   {
 73    if(s=='+' || s=='-') return 62;
 74    if(s=='/' || s=='_') return 63;
 75    if(s >= "0" && s <= "9") return +s + 52;
 76    return this._searchCharTable(s,this.base64);
 77   },
 78 
 79 /** charCodeAt emulation. Returns the code point of the input character
 80   * @param {string} input character
 81   * @returns {number} 16 bit character point. If input if not ASCII and utf8.js is not loaded, will return 0.
 82   */
 83   charCode: function(a)
 84   {
 85    var t = this.ascii_table;
 86    return (a.length == 1 && a <= "\xFF" ? t[a]
 87     : this._searchCharTable(a, this.utf8));
 88   },
 89 
 90 /** ASCII code of input character.
 91   * @param {string} input character
 92   * @returns {number} ASCII code of input. Unlike encoding.charCode, will always return 0 if input is non-ASCII.
 93   */
 94   a2b: function(a)
 95   {
 96    var t = this.ascii_table;
 97    return (a.length==1 && a <= "\xFF" ? t[a] : 0);
 98   },
 99 
100 /** ASCII character from its code.
101   * @param {number} input ASCII code, only first 8 bits are taken into account.
102   * @returns {string} associated ASCII character.
103   */
104   b2a: function(n)
105   {
106    var a = this.ascii+'';
107    return a[((n&255)>>>0)%a.length];
108   },
109 
110 /** fromCharCode emulation. Can create unicode characters.
111   * @param {number} input code point (truncated to 16 bits)
112   * @returns {string} UCS-2 character of requested code point.
113   */
114   fromCharCode: function(n)
115   {
116    var a = this.ascii+'', u = this.utf8+'';
117    if(n < 256) return a[(n>>>0)%a.length];
118    return u[(n>>>0)%u.length];
119   },
120 
121 /** Convert an ASCII string to an hexadecimal string
122   * @param {string} input must be ASCII (uses a2b internally)
123   * @returns {string} hex representation of input
124   */
125   astr2hstr: function(s)
126   {
127    var res = '', i = 0, s=s+'';
128    for(i=0; i<s.length; i++)
129     res += this.b2h(this.a2b(s[i]));
130    return res;
131   },
132 
133 /** Convert an hexadecimal string to ASCII.
134   * @param {string} input hex string
135   * @returns {string} ASCII equivalent
136   */
137   hstr2astr: function(s)
138   {
139    var i = 0, u = 0, c = '', res = "",
140        t = this.ascii+'', s = s + '';
141 
142    for(i=0; i<s.length; i++)
143    {
144     if(!(i&1)) c = s[i];
145     else
146     {
147      u = +('0x'+c+s[i]);
148      res += t[(u>>>0)%t.length];
149     }
150    }
151    return res;
152   },
153 
154 /** Encode a raw ASCII string back into a JavaScript string
155   * @param {string} input ASCII
156   * @returns {string} JavaScript unicode string representing the UTF-8 input.
157   */
158   utf8_encode: function(s)
159   {
160    var res = "", i = 0, c = 0, p = '',
161        buffer = [0,0,0,0], expected = [0,0];
162 
163    for(i=0; i < s.length; i++)
164    {
165     c = this.a2b(p = s[i]);
166     if(expected[0] != 0)
167     {
168      // Invalied continuation
169      if(c<128 || c > 191){expected=[0,0]; continue}
170      buffer[(expected[1]+1-expected[0]--)&3] = c;
171 
172      if(!expected[0])
173      {
174       res += this.fromCharCode(
175         expected[1]==1 ? (buffer[0]&31)<<6 | (buffer[1] & 63)
176          : (buffer[0] & 15)<<12 | (buffer[1] & 63)<<6 | (buffer[2] & 63));
177      }
178      else continue;
179     }
180     buffer[0] = c;
181 
182     if(c<128) res += p;
183     else if(c>191 && c<224) expected = [1,1];
184     else if(c>=224 && c<240) expected = [2,2];
185     // Otherwise, invalid head (ignored)
186    }
187 
188    return res;
189   },
190 
191 /** Decode an UTF-8 string to its raw ASCII equivalent.
192   * @param {string} input JavaScript string (containing unicode characters)
193   * @returns {string} decoded ASCII string
194   */
195   utf8_decode: function(s)
196   {
197    var res = "", i = 0, c = 0, s = s+'',
198        x = this.b2a(0);
199 
200    for(i=0; i<s.length; i++)
201    {
202     c = this.charCode(x = s[i]);
203     if(c < 128) res += x;
204     else if(c < 2048)
205      res += this.b2a((c>>6)|192)+this.b2a((c&63)|128);
206     else
207      res += this.b2a((c>>12)|224)+this.b2a(128|(c>>6)&63)+this.b2a(128|c&63);
208    }
209 
210    return res;
211   },
212 
213 /** Encode an ASCII string to base64
214   * @param {string} input ASCII
215   * @returns {string} base64 encoding of input.
216   */
217   base64_encode: function(s)
218   {
219    return this._base64_encode(s, false);
220   },
221 
222 /** Encode an ASCII string to url-compatible base64
223   * @param {string} input ASCII
224   * @returns {string} url-base64 encoding of input.
225   */
226   base64_urlencode: function(s)
227   {
228    return this._base64_encode(s, true);
229   },
230 
231   _base64_encode: function(s, url)
232   {
233    var res = "", i = 0, c = 0, s = s+'',
234        buf = [0,0], pad = !url ? '=' : '', p = '',
235        table = this.base64 + "0123456789" + (url ? '-_' : '+/'),
236        chr = function(i){return table[(i>>>0)%table.length]};
237 
238    for(i=0; i < s.length; i++)
239    {
240     c = this.a2b(s[i]);
241 
242     if(i%3 == 2)
243     {
244      c += (buf[1]<<8) + (buf[0]<<16);
245      res += chr((c>>>18)&63);
246      res += chr((c>>>12)&63);
247      res += chr((c>>>6)&63);
248      res += chr(c&63);
249      buf = [0, 0];
250     }
251     else buf[(i%3)&1] = c;
252    }
253 
254    // Padding
255    if(i%3 != 0)
256    {
257     c = (buf[1]<<8) + (buf[0]<<16);
258     res += chr((c>>>18)&63);
259     res += chr((c>>>12)&63);
260     res += (i%3==2)?chr((c>>>6)&63):pad;
261     res += pad;
262    }
263 
264    return res;
265   },
266 
267 /** Decode a base64-encoded string to ASCII
268   * @param {string} input base64 (can be url-safe or not)
269   * @returns {string} the decoded ASCII string.
270   */
271   base64_decode: function(s)
272   {
273    var s = s+'', res = "", buf = [0,0,0,0],
274        i = 0, x = '', c = 0;
275 
276    if((s.length&3) != 0) s+='=';
277    for(i=0; i < s.length; i++)
278    {
279     if((x = s[i]) == "=") break;
280     c = this.b64c(x);
281 
282     if((i&3) == 3)
283     {
284      c += (buf[2]<<6) + (buf[1]<<12) + (buf[0]<<18);
285      res += this.b2a((c>>>16)&255);
286      res += this.b2a((c>>>8)&255);
287      res += this.b2a(c&255);
288      buf = [0,0,0,0];
289     }
290     else buf[(i%4)&3] = c;
291    }
292 
293    // Padding
294    if((i&3)>1)
295    {
296     c = (buf[2]<<6) + (buf[1]<<12) + (buf[0]<<18);
297     res += this.b2a((c>>>16)&255);
298     if((i&3) == 3) res += this.b2a((c>>>8)&255);
299    }
300 
301    return res;
302   },
303  };
304 
305