1 /* base64x-1.1.30 (c) 2012-2022 Kenji Urushima | kjur.github.io/jsrsasign/license
  2  */
  3 /*
  4  * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library
  5  *
  6  * Copyright (c) 2012-2022 Kenji Urushima (kenji.urushima@gmail.com)
  7  *
  8  * This software is licensed under the terms of the MIT License.
  9  * https://kjur.github.io/jsrsasign/license
 10  *
 11  * The above copyright and license notice shall be 
 12  * included in all copies or substantial portions of the Software.
 13  */
 14 
 15 /**
 16  * @fileOverview
 17  * @name base64x-1.1.js
 18  * @author Kenji Urushima kenji.urushima@gmail.com
 19  * @version jsrsasign 10.5.25 base64x 1.1.30 (2022-Jun-23)
 20  * @since jsrsasign 2.1
 21  * @license <a href="https://kjur.github.io/jsrsasign/license/">MIT License</a>
 22  */
 23 
 24 var KJUR;
 25 if (typeof KJUR == "undefined" || !KJUR) KJUR = {};
 26 if (typeof KJUR.lang == "undefined" || !KJUR.lang) KJUR.lang = {};
 27 
 28 /**
 29  * String and its utility class <br/>
 30  * This class provides some static utility methods for string.
 31  * @class String and its utility class
 32  * @author Kenji Urushima
 33  * @version 1.0 (2016-Aug-05)
 34  * @since base64x 1.1.7 jsrsasign 5.0.13
 35  * @description
 36  * <br/>
 37  * This class provides static methods for string utility.
 38  * <dl>
 39  * <dt><b>STRING TYPE CHECKERS</b>
 40  * <dd>
 41  * <ul>
 42  * <li>{@link KJUR.lang.String.isInteger} - check whether argument is an integer</li>
 43  * <li>{@link KJUR.lang.String.isHex} - check whether argument is a hexadecimal string</li>
 44  * <li>{@link KJUR.lang.String.isBase64} - check whether argument is a Base64 encoded string</li>
 45  * <li>{@link KJUR.lang.String.isBase64URL} - check whether argument is a Base64URL encoded string</li>
 46  * <li>{@link KJUR.lang.String.isIntegerArray} - check whether argument is an array of integers</li>
 47  * <li>{@link KJUR.lang.String.isPrintable} - check whether argument is PrintableString accepted characters</li>
 48  * <li>{@link KJUR.lang.String.isIA5} - check whether argument is IA5String accepted characters</li>
 49  * <li>{@link KJUR.lang.String.isMail} - check whether argument is RFC 822 e-mail address format</li>
 50  * </ul>
 51  * </dl>
 52  */
 53 KJUR.lang.String = function() {};
 54 
 55 /**
 56  * Base64URL and supplementary functions for Tom Wu's base64.js library.<br/>
 57  * This class is just provide information about global functions
 58  * defined in 'base64x.js'. The 'base64x.js' script file provides
 59  * global functions for converting following data each other.
 60  * <ul>
 61  * <li>(ASCII) String</li>
 62  * <li>UTF8 String including CJK, Latin and other characters</li>
 63  * <li>byte array</li>
 64  * <li>hexadecimal encoded String</li>
 65  * <li>Full URIComponent encoded String (such like "%69%94")</li>
 66  * <li>Base64 encoded String</li>
 67  * <li>Base64URL encoded String</li>
 68  * </ul>
 69  * All functions in 'base64x.js' are defined in {@link global__} and not
 70  * in this class.
 71  * 
 72  * @class Base64URL and supplementary functions for Tom Wu's base64.js library
 73  * @author Kenji Urushima
 74  * @version 1.1 (07 May 2012)
 75  * @requires base64.js
 76  * @see <a href="https://kjur.github.io/jsjws/">'jwjws'(JWS JavaScript Library) home page https://kjur.github.io/jsjws/</a>
 77  * @see <a href="https://kjur.github.io/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page https://kjur.github.io/jsrsasign/</a>
 78  */
 79 function Base64x() {
 80 }
 81 
 82 // ==== string / byte array ================================
 83 /**
 84  * convert a string to an array of character codes
 85  * @name stoBA
 86  * @function
 87  * @param {String} s
 88  * @return {Array of Numbers} 
 89  */
 90 function stoBA(s) {
 91     var a = new Array();
 92     for (var i = 0; i < s.length; i++) {
 93 	a[i] = s.charCodeAt(i);
 94     }
 95     return a;
 96 }
 97 
 98 /**
 99  * convert an array of character codes to a string
100  * @name BAtos
101  * @function
102  * @param {Array of Numbers} a array of character codes
103  * @return {String} s
104  */
105 function BAtos(a) {
106     var s = "";
107     for (var i = 0; i < a.length; i++) {
108 	s = s + String.fromCharCode(a[i]);
109     }
110     return s;
111 }
112 
113 // ==== byte array / hex ================================
114 /**
115  * convert an array of bytes(Number) to hexadecimal string.<br/>
116  * @name BAtohex
117  * @function
118  * @param {Array of Numbers} a array of bytes
119  * @return {String} hexadecimal string
120  */
121 function BAtohex(a) {
122     var s = "";
123     for (var i = 0; i < a.length; i++) {
124 	var hex1 = a[i].toString(16);
125 	if (hex1.length == 1) hex1 = "0" + hex1;
126 	s = s + hex1;
127     }
128     return s;
129 }
130 
131 // ==== string / hex ================================
132 /**
133  * convert a ASCII string to a hexadecimal string of ASCII codes.<br/>
134  * NOTE: This can't be used for non ASCII characters.
135  * @name stohex
136  * @function
137  * @param {s} s ASCII string
138  * @return {String} hexadecimal string
139  */
140 function stohex(s) {
141     return BAtohex(stoBA(s));
142 }
143 
144 // ==== string / base64 ================================
145 /**
146  * convert a ASCII string to a Base64 encoded string.<br/>
147  * NOTE: This can't be used for non ASCII characters.
148  * @name stob64
149  * @function
150  * @param {s} s ASCII string
151  * @return {String} Base64 encoded string
152  */
153 function stob64(s) {
154     return hex2b64(stohex(s));
155 }
156 
157 // ==== string / base64url ================================
158 /**
159  * convert a ASCII string to a Base64URL encoded string.<br/>
160  * NOTE: This can't be used for non ASCII characters.
161  * @name stob64u
162  * @function
163  * @param {s} s ASCII string
164  * @return {String} Base64URL encoded string
165  */
166 function stob64u(s) {
167     return b64tob64u(hex2b64(stohex(s)));
168 }
169 
170 /**
171  * convert a Base64URL encoded string to a ASCII string.<br/>
172  * NOTE: This can't be used for Base64URL encoded non ASCII characters.
173  * @name b64utos
174  * @function
175  * @param {s} s Base64URL encoded string
176  * @return {String} ASCII string
177  */
178 function b64utos(s) {
179     return BAtos(b64toBA(b64utob64(s)));
180 }
181 
182 // ==== base64 / base64url ================================
183 /**
184  * convert a Base64 encoded string to a Base64URL encoded string.<br/>
185  * @name b64tob64u
186  * @function
187  * @param {String} s Base64 encoded string
188  * @return {String} Base64URL encoded string
189  * @example
190  * b64tob64u("ab+c3f/==") → "ab-c3f_"
191  */
192 function b64tob64u(s) {
193     s = s.replace(/\=/g, "");
194     s = s.replace(/\+/g, "-");
195     s = s.replace(/\//g, "_");
196     return s;
197 }
198 
199 /**
200  * convert a Base64URL encoded string to a Base64 encoded string.<br/>
201  * @name b64utob64
202  * @function
203  * @param {String} s Base64URL encoded string
204  * @return {String} Base64 encoded string
205  * @example
206  * b64utob64("ab-c3f_") → "ab+c3f/=="
207  */
208 function b64utob64(s) {
209     if (s.length % 4 == 2) s = s + "==";
210     else if (s.length % 4 == 3) s = s + "=";
211     s = s.replace(/-/g, "+");
212     s = s.replace(/_/g, "/");
213     return s;
214 }
215 
216 // ==== hex / base64url ================================
217 /**
218  * convert a hexadecimal string to a Base64URL encoded string.<br/>
219  * @name hextob64u
220  * @function
221  * @param {String} s hexadecimal string
222  * @return {String} Base64URL encoded string
223  * @description
224  * convert a hexadecimal string to a Base64URL encoded string.
225  * NOTE: If leading "0" is omitted and odd number length for
226  * hexadecimal leading "0" is automatically added.
227  */
228 function hextob64u(s) {
229     if (s.length % 2 == 1) s = "0" + s;
230     return b64tob64u(hex2b64(s));
231 }
232 
233 /**
234  * convert a Base64URL encoded string to a hexadecimal string.<br/>
235  * @name b64utohex
236  * @function
237  * @param {String} s Base64URL encoded string
238  * @return {String} hexadecimal string
239  */
240 function b64utohex(s) {
241     return b64tohex(b64utob64(s));
242 }
243 
244 // ==== utf8 / base64url ================================
245 
246 /**
247  * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.<br/>
248  * @name utf8tob64u
249  * @function
250  * @param {String} s UTF-8 encoded string
251  * @return {String} Base64URL encoded string
252  * @since 1.1
253  * @example
254  * utf8tob64u("あ") → "44GC"
255  * utf8tob64u("aaa") → "YWFh"
256  */
257 
258 /**
259  * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
260  * @name b64utoutf8
261  * @function
262  * @param {String} s Base64URL encoded string
263  * @return {String} UTF-8 encoded string
264  * @since 1.1
265  * @example
266  * b64utoutf8("44GC") → "あ"
267  * b64utoutf8("YWFh") → "aaa"
268  */
269 
270 var utf8tob64u, b64utoutf8;
271 
272 if (typeof Buffer === 'function') {
273   utf8tob64u = function (s) {
274     return b64tob64u(Buffer.from(s, 'utf8').toString('base64'));
275   };
276 
277   b64utoutf8 = function (s) {
278     return Buffer.from(b64utob64(s), 'base64').toString('utf8');
279   };
280 } else {
281   utf8tob64u = function (s) {
282     return hextob64u(uricmptohex(encodeURIComponentAll(s)));
283   };
284 
285   b64utoutf8 = function (s) {
286     return decodeURIComponent(hextouricmp(b64utohex(s)));
287   };
288 }
289 
290 // ==== utf8 / base64url ================================
291 /**
292  * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.<br/>
293  * @name utf8tob64
294  * @function
295  * @param {String} s UTF-8 encoded string
296  * @return {String} Base64 encoded string
297  * @since 1.1.1
298  */
299 function utf8tob64(s) {
300   return hex2b64(uricmptohex(encodeURIComponentAll(s)));
301 }
302 
303 /**
304  * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
305  * @name b64toutf8
306  * @function
307  * @param {String} s Base64 encoded string
308  * @return {String} UTF-8 encoded string
309  * @since 1.1.1
310  */
311 function b64toutf8(s) {
312   return decodeURIComponent(hextouricmp(b64tohex(s)));
313 }
314 
315 // ==== utf8 / hex ================================
316 /**
317  * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.<br/>
318  * @name utf8tohex
319  * @function
320  * @param {String} s UTF-8 encoded string
321  * @return {String} hexadecimal encoded string
322  * @since 1.1.1
323  */
324 function utf8tohex(s) {
325   return uricmptohex(encodeURIComponentAll(s)).toLowerCase();
326 }
327 
328 /**
329  * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.<br/>
330  * Note that when input is improper hexadecimal string as UTF-8 string, this function returns
331  * 'null'.
332  * @name hextoutf8
333  * @function
334  * @param {String} s hexadecimal encoded string
335  * @return {String} UTF-8 encoded string or null
336  * @since 1.1.1
337  */
338 function hextoutf8(s) {
339   try {
340     return decodeURIComponent(hextouricmp(s));
341   } catch(ex) {
342     return null;
343   }
344 }
345 
346 // ==== iso8859-1 latin1 / utf8 ===================
347 /**
348  * convert a hexadecimal ISO 8859-1 latin string to UTF-8 string<br/>
349  * @name iso88591hextoutf8
350  * @function
351  * @param {String} h hexadecimal ISO 8859-1 latin string
352  * @return {String} UTF-8 string
353  * @since jsrsasign 10.5.12 base64x 1.1.25
354  * @see utf8toiso88591hex
355  *
356  * @example
357  * iso88591hextoutf8("41a9fa") → "A©ú"
358  */
359 function iso88591hextoutf8(h) {
360     return hextoutf8(iso88591hextoutf8hex(h));
361 }
362 
363 /**
364  * convert UTF-8 string to a hexadecimal ISO 8859-1 latin string<br/>
365  * @name utf8toiso88591hex
366  * @function
367  * @param {String} s hexadecimal ISO 8859-1 latin string
368  * @return {String} UTF-8 string
369  * @since jsrsasign 10.5.12 base64x 1.1.25
370  * @see iso88591hextoutf8
371  *
372  * @example
373  * utf8toiso88591hex("A©ú") → "41a9fa"
374  */
375 function utf8toiso88591hex(s) {
376     return utf8hextoiso88591hex(utf8tohex(s));
377 }
378 
379 /**
380  * convert a hexadecimal ISO 8859-1 latin string to UTF-8 hexadecimal string<br/>
381  * @name iso88591hextoutf8hex
382  * @function
383  * @param {String} h hexadecimal ISO 8859-1 latin string
384  * @return {String} UTF-8 hexadecimal string
385  * @since jsrsasign 10.5.12 base64x 1.1.25
386  * @see iso88591hextoutf8
387  * @see utf8hextoiso88591hex
388  *
389  * @example
390  * iso88591hextoutf8hex("41a9fa") → "41c2a9c3ba"
391  */
392 function iso88591hextoutf8hex(h) {
393     var a = h.match(/.{1,2}/g);
394     var a2 = [];
395     for (var i = 0; i < a.length; i++) {
396 	var di = parseInt(a[i], 16);
397 	if (0xa1 <= di && di <= 0xbf) {
398 	    a2.push("c2");
399 	    a2.push(a[i]);
400 	} else if (0xc0 <= di && di <= 0xff) {
401 	    a2.push("c3");
402 	    a2.push((di - 64).toString(16));
403 	} else {
404 	    a2.push(a[i]);
405 	}
406     }
407     return a2.join('');
408 }
409 
410 /**
411  * convert UTF-8 string to a hexadecimal ISO 8859-1 latin string<br/>
412  * @name utf8hextoiso88591hex
413  * @function
414  * @param {String} h hexadecimal UTF-8 string
415  * @return {String} hexadecimal ISO 8859-1 latin string
416  * @since jsrsasign 10.5.12 base64x 1.1.25
417  * @see iso88591hextoutf8hex
418  * @see utf8toiso88591hex
419  *
420  * @example
421  * utf8hextoiso88591hex("41c2a9c3ba") → "41a9fa"
422  */
423 function utf8hextoiso88591hex(h) {
424     var a = h.match(/.{1,2}/g);
425     var a2 = [];
426     for (var i = 0; i < a.length; i++) {
427 	if (a[i] == 'c2') {
428 	    i++;
429 	    a2.push(a[i]);
430 	} else if (a[i] == 'c3') {
431 	    i++;
432 	    var ci = a[i];
433 	    var di = parseInt(a[i], 16) + 64;
434 	    a2.push(di.toString(16));
435 	} else {
436 	    a2.push(a[i]);
437 	}
438     }
439     return a2.join('');
440 }
441 
442 // ==== rstr / hex ================================
443 /**
444  * convert a hexadecimal encoded string to raw string including non printable characters.<br/>
445  * @name hextorstr
446  * @function
447  * @param {String} s hexadecimal encoded string
448  * @return {String} raw string
449  * @since 1.1.2
450  * @example
451  * hextorstr("610061") → "a\x00a"
452  */
453 function hextorstr(sHex) {
454     var s = "";
455     for (var i = 0; i < sHex.length - 1; i += 2) {
456         s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16));
457     }
458     return s;
459 }
460 
461 /**
462  * convert a raw string including non printable characters to hexadecimal encoded string.<br/>
463  * @name rstrtohex
464  * @function
465  * @param {String} s raw string
466  * @return {String} hexadecimal encoded string
467  * @since 1.1.2
468  * @example
469  * rstrtohex("a\x00a") → "610061"
470  */
471 function rstrtohex(s) {
472     var result = "";
473     for (var i = 0; i < s.length; i++) {
474         result += ("0" + s.charCodeAt(i).toString(16)).slice(-2);
475     }
476     return result;
477 }
478 
479 // ==== hex / b64nl =======================================
480 
481 /**
482  * convert a hexadecimal string to Base64 encoded string<br/>
483  * @name hextob64
484  * @function
485  * @param {String} s hexadecimal string
486  * @return {String} resulted Base64 encoded string
487  * @since base64x 1.1.3
488  * @description
489  * This function converts from a hexadecimal string to Base64 encoded
490  * string without new lines.
491  * @example
492  * hextob64("616161") → "YWFh"
493  */
494 function hextob64(s) {
495     return hex2b64(s);
496 }
497 
498 /**
499  * convert a hexadecimal string to Base64 encoded string with new lines<br/>
500  * @name hextob64nl
501  * @function
502  * @param {String} s hexadecimal string
503  * @return {String} resulted Base64 encoded string with new lines
504  * @since base64x 1.1.3
505  * @description
506  * This function converts from a hexadecimal string to Base64 encoded
507  * string with new lines for each 64 characters. This is useful for
508  * PEM encoded file.
509  * @example
510  * hextob64nl("123456789012345678901234567890123456789012345678901234567890")
511  * →
512  * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line
513  * OTAxMjM0NTY3ODkwCg==
514  */
515 function hextob64nl(s) {
516     var b64 = hextob64(s);
517     var b64nl = b64.replace(/(.{64})/g, "$1\r\n");
518     b64nl = b64nl.replace(/\r\n$/, '');
519     return b64nl;
520 }
521 
522 /**
523  * convert a Base64 encoded string with new lines to a hexadecimal string<br/>
524  * @name b64nltohex
525  * @function
526  * @param {String} s Base64 encoded string with new lines
527  * @return {String} hexadecimal string
528  * @since base64x 1.1.3
529  * @description
530  * This function converts from a Base64 encoded
531  * string with new lines to a hexadecimal string.
532  * This is useful to handle PEM encoded file.
533  * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=)
534  * including new line.
535  * @example
536  * hextob64nl(
537  * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" +
538  * "OTAxMjM0NTY3ODkwCg==\r\n")
539  * →
540  * "123456789012345678901234567890123456789012345678901234567890"
541  */
542 function b64nltohex(s) {
543     var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, '');
544     var hex = b64tohex(b64);
545     return hex;
546 } 
547 
548 // ==== hex / pem =========================================
549 
550 /**
551  * get PEM string from hexadecimal data and header string
552  * @name hextopem
553  * @function
554  * @param {String} dataHex hexadecimal string of PEM body
555  * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
556  * @return {String} PEM formatted string of input data
557  * @since jsrasign 7.2.1 base64x 1.1.12
558  * @description
559  * This function converts a hexadecimal string to a PEM string with
560  * a specified header. Its line break will be CRLF("\r\n").
561  * @example
562  * hextopem('616161', 'RSA PRIVATE KEY') →
563  * -----BEGIN PRIVATE KEY-----
564  * YWFh
565  * -----END PRIVATE KEY-----
566  */
567 function hextopem(dataHex, pemHeader) {
568     var pemBody = hextob64nl(dataHex);
569     return "-----BEGIN " + pemHeader + "-----\r\n" + 
570         pemBody + 
571         "\r\n-----END " + pemHeader + "-----\r\n";
572 }
573 
574 /**
575  * get hexacedimal string from PEM format data<br/>
576  * @name pemtohex
577  * @function
578  * @param {String} s PEM formatted string
579  * @param {String} sHead PEM header string without BEGIN/END(OPTION)
580  * @return {String} hexadecimal string data of PEM contents
581  * @since jsrsasign 7.2.1 base64x 1.1.12
582  * @description
583  * This static method gets a hexacedimal string of contents 
584  * from PEM format data. You can explicitly specify PEM header 
585  * by sHead argument. 
586  * Any space characters such as white space or new line
587  * will be omitted.<br/>
588  * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex}
589  * have been deprecated since jsrsasign 7.2.1. 
590  * Please use this method instead.
591  * NOTE2: From jsrsasign 8.0.14 this can process multi
592  * "BEGIN...END" section such as "EC PRIVATE KEY" with "EC PARAMETERS".
593  * @example
594  * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..."
595  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..."
596  * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..."
597  * pemtohex("-----BEGIN EC PARAMETERS...----BEGIN EC PRIVATE KEY...." → "3082..."
598  */
599 function pemtohex(s, sHead) {
600     if (s.indexOf("-----BEGIN ") == -1)
601         throw "can't find PEM header: " + sHead;
602 
603     if (sHead !== undefined) {
604         s = s.replace(new RegExp('^[^]*-----BEGIN ' + sHead + '-----'), '');
605         s = s.replace(new RegExp('-----END ' + sHead + '-----[^]*$'), '');
606     } else {
607         s = s.replace(/^[^]*-----BEGIN [^-]+-----/, '');
608         s = s.replace(/-----END [^-]+-----[^]*$/, '');
609     }
610     return b64nltohex(s);
611 }
612 
613 // ==== hex / ArrayBuffer =================================
614 
615 /**
616  * convert a hexadecimal string to an ArrayBuffer<br/>
617  * @name hextoArrayBuffer
618  * @function
619  * @param {String} hex hexadecimal string
620  * @return {ArrayBuffer} ArrayBuffer
621  * @since jsrsasign 6.1.4 base64x 1.1.8
622  * @description
623  * This function converts from a hexadecimal string to an ArrayBuffer.
624  * @example
625  * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1]
626  */
627 function hextoArrayBuffer(hex) {
628     if (hex.length % 2 != 0) throw "input is not even length";
629     if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal";
630 
631     var buffer = new ArrayBuffer(hex.length / 2);
632     var view = new DataView(buffer);
633 
634     for (var i = 0; i < hex.length / 2; i++) {
635 	view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
636     }
637 
638     return buffer;
639 }
640 
641 // ==== ArrayBuffer / hex =================================
642 
643 /**
644  * convert an ArrayBuffer to a hexadecimal string<br/>
645  * @name ArrayBuffertohex
646  * @function
647  * @param {ArrayBuffer} buffer ArrayBuffer
648  * @return {String} hexadecimal string
649  * @since jsrsasign 6.1.4 base64x 1.1.8
650  * @description
651  * This function converts from an ArrayBuffer to a hexadecimal string.
652  * @example
653  * var buffer = new ArrayBuffer(3);
654  * var view = new DataView(buffer);
655  * view.setUint8(0, 0xfa);
656  * view.setUint8(1, 0xfb);
657  * view.setUint8(2, 0x01);
658  * ArrayBuffertohex(buffer) → "fafb01"
659  */
660 function ArrayBuffertohex(buffer) {
661     var hex = "";
662     var view = new DataView(buffer);
663 
664     for (var i = 0; i < buffer.byteLength; i++) {
665 	hex += ("00" + view.getUint8(i).toString(16)).slice(-2);
666     }
667 
668     return hex;
669 }
670 
671 // ==== zulu / int =================================
672 /**
673  * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br>
674  * @name zulutomsec
675  * @function
676  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
677  * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
678  * @since jsrsasign 7.1.3 base64x 1.1.9
679  * @description
680  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
681  * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time
682  * (i.e. Jan 1 1970 0:00:00 UTC). 
683  * Argument string may have fraction of seconds and
684  * its length is one or more digits such as "20170410235959.1234567Z".
685  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
686  * If year "YY" is equal or greater than 50 then it is 19YY.
687  * @example
688  * zulutomsec(  "071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
689  * zulutomsec(  "071231235959.1Z")     → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT
690  * zulutomsec(  "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT
691  * zulutomsec("20071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
692  * zulutomsec(  "931231235959Z")       → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT
693  */
694 function zulutomsec(s) {
695     var year, month, day, hour, min, sec, msec, d;
696     var sYear, sFrac, sMsec, matchResult;
697 
698     matchResult = s.match(/^(\d{2}|\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/);
699 
700     if (matchResult) {
701         sYear = matchResult[1];
702 	year = parseInt(sYear);
703         if (sYear.length === 2) {
704 	    if (50 <= year && year < 100) {
705 		year = 1900 + year;
706 	    } else if (0 <= year && year < 50) {
707 		year = 2000 + year;
708 	    }
709 	}
710 	month = parseInt(matchResult[2]) - 1;
711 	day = parseInt(matchResult[3]);
712 	hour = parseInt(matchResult[4]);
713 	min = parseInt(matchResult[5]);
714 	sec = parseInt(matchResult[6]);
715 	msec = 0;
716 
717 	sFrac = matchResult[7];
718 	if (sFrac !== "") {
719 	    sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012
720 	    msec = parseInt(sMsec);
721 	}
722 	return Date.UTC(year, month, day, hour, min, sec, msec);
723     }
724     throw new Error("unsupported zulu format: " + s);
725 }
726 
727 /**
728  * GeneralizedTime or UTCTime string to seconds from Unix origin<br>
729  * @name zulutosec
730  * @function
731  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
732  * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
733  * @since jsrsasign 7.1.3 base64x 1.1.9
734  * @description
735  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
736  * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time
737  * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 
738  * however result value will be omitted.
739  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
740  * If year "YY" is equal or greater than 50 then it is 19YY.
741  * @example
742  * zulutosec(  "071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
743  * zulutosec(  "071231235959.1Z")     → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
744  * zulutosec("20071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
745  */
746 function zulutosec(s) {
747     return Math.round(zulutomsec(s) / 1000.0);
748 }
749 
750 // ==== zulu / Date =================================
751 
752 /**
753  * GeneralizedTime or UTCTime string to Date object<br>
754  * @name zulutodate
755  * @function
756  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
757  * @return {Date} Date object for specified time
758  * @since jsrsasign 7.1.3 base64x 1.1.9
759  * @description
760  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
761  * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object.
762  * Argument string may have fraction of seconds and
763  * its length is one or more digits such as "20170410235959.1234567Z".
764  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
765  * If year "YY" is equal or greater than 50 then it is 19YY.
766  * @example
767  * zulutodate(  "071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
768  * zulutodate(  "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT"
769  * zulutodate("20071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
770  * zulutodate(  "071231235959.34").getMilliseconds() → 340
771  */
772 function zulutodate(s) {
773     return new Date(zulutomsec(s));
774 }
775 
776 // ==== Date / zulu =================================
777 
778 /**
779  * Date object to zulu time string<br>
780  * @name datetozulu
781  * @function
782  * @param {Date} d Date object for specified time
783  * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY
784  * @param {Boolean} flagMilli if this is true result concludes milliseconds
785  * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
786  * @since jsrsasign 7.2.0 base64x 1.1.11
787  * @description
788  * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
789  * UTCTime string (i.e. YYMMDDHHmmSSZ).
790  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
791  * If year "YY" is equal or greater than 50 then it is 19YY.
792  * If flagMilli is true its result concludes milliseconds such like
793  * "20170520235959.42Z". 
794  * @example
795  * d = new Date(Date.UTC(2017,4,20,23,59,59,670));
796  * datetozulu(d) → "20170520235959Z"
797  * datetozulu(d, true) → "170520235959Z"
798  * datetozulu(d, false, true) → "20170520235959.67Z"
799  */
800 function datetozulu(d, flagUTCTime, flagMilli) {
801     var s;
802     var year = d.getUTCFullYear();
803     if (flagUTCTime) {
804 	if (year < 1950 || 2049 < year) 
805 	    throw "not proper year for UTCTime: " + year;
806 	s = ("" + year).slice(-2);
807     } else {
808 	s = ("000" + year).slice(-4);
809     }
810     s += ("0" + (d.getUTCMonth() + 1)).slice(-2);
811     s += ("0" + d.getUTCDate()).slice(-2);
812     s += ("0" + d.getUTCHours()).slice(-2);
813     s += ("0" + d.getUTCMinutes()).slice(-2);
814     s += ("0" + d.getUTCSeconds()).slice(-2);
815     if (flagMilli) {
816 	var milli = d.getUTCMilliseconds();
817 	if (milli !== 0) {
818 	    milli = ("00" + milli).slice(-3);
819 	    milli = milli.replace(/0+$/g, "");
820 	    s += "." + milli;
821 	}
822     }
823     s += "Z";
824     return s;
825 }
826 
827 // ==== URIComponent / hex ================================
828 /**
829  * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/>
830  * @name uricmptohex
831  * @function
832  * @param {String} s URIComponent string such like "%67%68"
833  * @return {String} hexadecimal string
834  * @since 1.1
835  */
836 function uricmptohex(s) {
837   return s.replace(/%/g, "");
838 }
839 
840 /**
841  * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/>
842  * @name hextouricmp
843  * @function
844  * @param {String} s hexadecimal string
845  * @return {String} URIComponent string such like "%67%68"
846  * @since 1.1
847  */
848 function hextouricmp(s) {
849   return s.replace(/(..)/g, "%$1");
850 }
851 
852 // ==== hex / ipv6 =================================
853 
854 /**
855  * convert any IPv6 address to a 16 byte hexadecimal string
856  * @function
857  * @param s string of IPv6 address
858  * @return {String} 16 byte hexadecimal string of IPv6 address
859  * @description
860  * This function converts any IPv6 address representation string
861  * to a 16 byte hexadecimal string of address.
862  * @example
863  * 
864  */
865 function ipv6tohex(s) {
866   var msgMalformedAddress = "malformed IPv6 address";
867   if (! s.match(/^[0-9A-Fa-f:]+$/))
868     throw msgMalformedAddress;
869 
870   // 1. downcase
871   s = s.toLowerCase();
872 
873   // 2. expand ::
874   var num_colon = s.split(':').length - 1;
875   if (num_colon < 2) throw msgMalformedAddress;
876   var colon_replacer = ':'.repeat(7 - num_colon + 2);
877   s = s.replace('::', colon_replacer);
878 
879   // 3. fill zero
880   var a = s.split(':');
881   if (a.length != 8) throw msgMalformedAddress;
882   for (var i = 0; i < 8; i++) {
883     a[i] = ("0000" + a[i]).slice(-4);
884   }
885   return a.join('');
886 }
887 
888 /**
889  * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/>
890  * @name hextoipv6
891  * @function
892  * @param {String} s hexadecimal string of 16 byte IPv6 address
893  * @return {String} IPv6 address string canonicalized by RFC 5952
894  * @since jsrsasign 8.0.10 base64x 1.1.13
895  * @description
896  * This function converts a 16 byte hexadecimal string to 
897  * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a>
898  * canonicalized IPv6 address string.
899  * @example
900  * hextoipv6("871020010db8000000000000000000000004") &rarr "2001:db8::4"
901  * hextoipv6("871020010db8000000000000000000") &rarr raise exception
902  * hextoipv6("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception
903  */
904 function hextoipv6(s) {
905     if (! s.match(/^[0-9A-Fa-f]{32}$/))
906 	throw new Error("malformed IPv6 address: " + s);
907 
908     // 1. downcase
909     s = s.toLowerCase();
910 
911     // 2. split 4 > ["0123", "00a4", "0000", ..., "ffff"]
912     var a = s.match(/.{1,4}/g);
913 
914     // 3. trim leading 0 for items and join > "123:a4:0:...:ffff"
915     a = a.map(function(s){return s.replace(/^0+/, '')});
916     a = a.map(function(s){return s == '' ? '0' : s});
917     s = ':' + a.join(':') + ':';
918 
919     // 4. find shrinkable candidates :0:0:..:0:
920     var aZero = s.match(/:(0:){2,}/g);
921 
922     // 5. no shrinkable
923     if (aZero == null) return s.slice(1, -1);
924 
925     // 6. fix max length zero(:0:...:0:)
926     var sMaxZero = aZero.sort().slice(-1)[0];
927 
928     // 7. replace shrinked
929     s = s.replace(sMaxZero.substr(0, sMaxZero.length - 1), ':');
930 
931     // 8. trim leading ':' if not '::'
932     if (s.substr(0, 2) != '::') s = s.substr(1);
933 
934     // 9. trim tail ':' if not '::'
935     if (s.substr(-2, 2) != '::') s = s.substr(0, s.length - 1);
936 
937     return s;
938 }
939 
940 // ==== hex / ip =================================
941 
942 /**
943  * convert a hexadecimal string to IP addresss<br/>
944  * @name hextoip
945  * @function
946  * @param {String} s hexadecimal string of IP address
947  * @return {String} IP address string
948  * @since jsrsasign 8.0.10 base64x 1.1.13
949  * @see hextoipv6
950  * @see iptohex
951  *
952  * @description
953  * This function converts a hexadecimal string of IPv4 or 
954  * IPv6 address to IPv4 or IPv6 address string.
955  * If byte length is not 4 nor 16, this returns a
956  * hexadecimal string without conversion.
957  * <br/>
958  * NOTE: From jsrsasign 10.5.17, CIDR subnet mask notation also supported.
959  *
960  * @example
961  * hextoip("c0a80101") → "192.168.1.1"
962  * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4"
963  * hextoip("c0a80100ffffff00") → "192.168.1.0/24"
964  * hextoip("c0a801010203") → "c0a801010203" // wrong 6 bytes
965  * hextoip("zzz")) → raise exception because of not hexadecimal
966  */
967 function hextoip(s) {
968     var malformedErr = new Error("malformed hex value");
969     if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))
970 	throw malformedErr;
971     if (s.length == 8) { // ipv4
972 	var ip;
973 	try {
974 	    ip = parseInt(s.substr(0, 2), 16) + "." +
975  		 parseInt(s.substr(2, 2), 16) + "." +
976 		 parseInt(s.substr(4, 2), 16) + "." +
977 		 parseInt(s.substr(6, 2), 16);
978 	    return ip;
979 	} catch (ex) {
980 	    throw malformedErr;
981 	}
982   } else if (s.length == 16) {
983       try {
984 	  return hextoip(s.substr(0, 8)) + "/" + ipprefixlen(s.substr(8));
985       } catch (ex) {
986 	  throw malformedErr;
987       }
988   } else if (s.length == 32) {
989       return hextoipv6(s);
990   } else if (s.length == 64) {
991       try {
992 	  return hextoipv6(s.substr(0, 32)) + "/" + ipprefixlen(s.substr(32));
993       } catch (ex) {
994 	  throw malformedErr;
995       }
996       return 
997   } else {
998     return s;
999   }
1000 }
1001 
1002 /*
1003  * convert subnet mask hex to ip address prefix length<br/>
1004  * @name ipprefixlen
1005  * @param {string} hMask hexadecimal string of ipv4/6 subnet mask (ex. "ffffff00" for v4 class C)
1006  * @return {nummber} ip address prefix length (ex. 24 for IPv4 class C)
1007  */
1008 function ipprefixlen(hMask) {
1009     var malformedErr = new Error("malformed mask");
1010     var bMask;
1011     try {
1012 	bMask = new BigInteger(hMask, 16).toString(2);
1013     } catch(ex) {
1014 	throw malformedErr;
1015     }
1016     if (! bMask.match(/^1*0*$/)) throw malformedErr;
1017     return bMask.replace(/0+$/, '').length;
1018 }
1019 
1020 /**
1021  * convert IPv4/v6 addresss to a hexadecimal string<br/>
1022  * @name iptohex
1023  * @function
1024  * @param {String} s IPv4/v6 address string
1025  * @return {String} hexadecimal string of IP address
1026  * @since jsrsasign 8.0.12 base64x 1.1.14
1027  * @see hextoip
1028  * @see ipv6tohex
1029  *
1030  * @description
1031  * This function converts IPv4 or IPv6 address string to
1032  * a hexadecimal string of IPv4 or IPv6 address.
1033  * <br/>
1034  * NOTE: From jsrsasign 10.5.17, CIDR net mask notation also supported.
1035  *
1036  * @example
1037  * iptohex("192.168.1.1") → "c0a80101"
1038  * iptohex("2001:db8::4") → "871020010db8000000000000000000000004"
1039  * iptohex("192.168.1.1/24") → "c0a80101ffffff00"
1040  * iptohex("2001:db8::/120") → "871020010db8000000000000000000000000ffffffffffffffffffffffffffffffffff00"
1041  * iptohex("zzz")) → raise exception
1042  */
1043 function iptohex(s) {
1044     var malformedErr = new Error("malformed IP address");
1045     s = s.toLowerCase(s);
1046 
1047     if (! s.match(/^[0-9a-f.:/]+$/) ) throw malformedErr;
1048 
1049     if (s.match(/^[0-9.]+$/)) {
1050 	var a = s.split(".");
1051 	if (a.length !== 4) throw malformedErr;
1052 	var hex = "";
1053 	try {
1054 	    for (var i = 0; i < 4; i++) {
1055 		var d = parseInt(a[i]);
1056 		hex += ("0" + d.toString(16)).slice(-2);
1057 	    }
1058 	    return hex;
1059 	} catch(ex) {
1060 	    throw malformedErr;
1061 	}
1062     } else if (s.match(/^[0-9.]+\/[0-9]+$/)) {
1063 	var aItem = s.split("/");
1064 	return iptohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 32);
1065     } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) {
1066 	return ipv6tohex(s);
1067     } else if (s.match(/^[0-9a-f:]+\/[0-9]+$/) && s.indexOf(":") !== -1) {
1068 	var aItem = s.split("/");
1069 	return ipv6tohex(aItem[0]) + ipnetmask(parseInt(aItem[1]), 128);
1070     } else {
1071 	throw malformedErr;
1072     }
1073 }
1074 
1075 /*
1076  * convert ip prefix length to net mask octets<br/>
1077  * @param {number} prefixlen ip prefix length value (ex. 24 for IPv4 class C)
1078  * @param {number} len ip address length (ex. 32 for IPv4 and 128 for IPv6)
1079  * @return {string} hexadecimal string of net mask octets
1080  * @example
1081  * ipnetmask(24, 32) → "ffffff00" 
1082  * ipnetmask(120, 128) → "ffffffffffffffffffffffffffffff00"
1083  */
1084 function ipnetmask(prefixlen, len) {
1085     if (len == 32 && prefixlen == 0) return "00000000"; // v4
1086     if (len == 128 && prefixlen == 0) return "00000000000000000000000000000000"; // v6
1087     var b = Array(prefixlen + 1).join("1") + Array(len - prefixlen + 1).join("0");
1088     return new BigInteger(b, 2).toString(16);
1089 }
1090 
1091 // ==== ucs2hex / utf8 ==============================
1092 
1093 /**
1094  * convert UCS-2 hexadecimal stirng to UTF-8 string<br/>
1095  * @name ucs2hextoutf8
1096  * @function
1097  * @param {String} s hexadecimal string of UCS-2 string (ex. "0066")
1098  * @return {String} UTF-8 string
1099  * @since jsrsasign 10.1.13 base64x 1.1.20
1100  * @description
1101  * This function converts hexadecimal value of UCS-2 string to 
1102  * UTF-8 string.
1103  * @example
1104  * ucs2hextoutf8("006600fc0072") &rarr "für"
1105  */
1106 /*
1107 See: http://nomenclator.la.coocan.jp/unicode/ucs_utf.htm
1108 UCS-2 to UTF-8
1109 UCS-2 code point | UCS-2 bytes       | UTF-8 bytes
1110 U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx (1 byte)
1111 U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx 10yyyyyy (2 byte)
1112 U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz (3 byte)
1113  */
1114 function ucs2hextoutf8(s) {
1115     function _conv(s) {
1116 	var i1 = parseInt(s.substr(0, 2), 16);
1117 	var i2 = parseInt(s.substr(2), 16);
1118 	if (i1 == 0 & i2 < 0x80) { // 1 byte
1119 	    return String.fromCharCode(i2);
1120 	}
1121 	if (i1 < 8) { // 2 bytes
1122 	    var u1 = 0xc0 | ((i1 & 0x07) << 3) | ((i2 & 0xc0) >> 6);
1123 	    var u2 = 0x80 | (i2 & 0x3f);
1124 	    return hextoutf8(u1.toString(16) + u2.toString(16));
1125 	}
1126 	// 3 bytes
1127 	var u1 = 0xe0 | ((i1 & 0xf0) >> 4);
1128 	var u2 = 0x80 | ((i1 & 0x0f) << 2) | ((i2 & 0xc0) >> 6);
1129 	var u3 = 0x80 | (i2 & 0x3f);
1130 	return hextoutf8(u1.toString(16) + u2.toString(16) + u3.toString(16));
1131     }
1132     var a = s.match(/.{4}/g);
1133     var a2 = a.map(_conv);
1134     return a2.join("");
1135 }
1136 
1137 // ==== URIComponent ================================
1138 /**
1139  * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/>
1140  * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not
1141  * converted to "%xx" format by builtin 'encodeURIComponent()' function.
1142  * However this 'encodeURIComponentAll()' function will convert 
1143  * all of characters into "%xx" format.
1144  * @name encodeURIComponentAll
1145  * @function
1146  * @param {String} s hexadecimal string
1147  * @return {String} URIComponent string such like "%67%68"
1148  * @since 1.1
1149  */
1150 function encodeURIComponentAll(u8) {
1151   var s = encodeURIComponent(u8);
1152   var s2 = "";
1153   for (var i = 0; i < s.length; i++) {
1154     if (s[i] == "%") {
1155       s2 = s2 + s.substr(i, 3);
1156       i = i + 2;
1157     } else {
1158       s2 = s2 + "%" + stohex(s[i]);
1159     }
1160   }
1161   return s2;
1162 }
1163 
1164 // ==== new lines ================================
1165 /**
1166  * convert all DOS new line("\r\n") to UNIX new line("\n") in 
1167  * a String "s".
1168  * @name newline_toUnix
1169  * @function
1170  * @param {String} s string 
1171  * @return {String} converted string
1172  */
1173 function newline_toUnix(s) {
1174     s = s.replace(/\r\n/mg, "\n");
1175     return s;
1176 }
1177 
1178 /**
1179  * convert all UNIX new line("\r\n") to DOS new line("\n") in 
1180  * a String "s".
1181  * @name newline_toDos
1182  * @function
1183  * @param {String} s string 
1184  * @return {String} converted string
1185  */
1186 function newline_toDos(s) {
1187     s = s.replace(/\r\n/mg, "\n");
1188     s = s.replace(/\n/mg, "\r\n");
1189     return s;
1190 }
1191 
1192 // ==== string type checker ===================
1193 
1194 /**
1195  * check whether a string is an integer string or not<br/>
1196  * @name isInteger
1197  * @memberOf KJUR.lang.String
1198  * @function
1199  * @static
1200  * @param {String} s input string
1201  * @return {Boolean} true if a string "s" is an integer string otherwise false
1202  * @since base64x 1.1.7 jsrsasign 5.0.13
1203  * @example
1204  * KJUR.lang.String.isInteger("12345") → true
1205  * KJUR.lang.String.isInteger("123ab") → false
1206  */
1207 KJUR.lang.String.isInteger = function(s) {
1208     if (s.match(/^[0-9]+$/)) {
1209 	return true;
1210     } else if (s.match(/^-[0-9]+$/)) {
1211 	return true;
1212     } else {
1213 	return false;
1214     }
1215 };
1216 
1217 /**
1218  * check whether a string is an hexadecimal string or not (DEPRECATED)<br/>
1219  * @name isHex
1220  * @memberOf KJUR.lang.String
1221  * @function
1222  * @static
1223  * @param {String} s input string
1224  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1225  * @since base64x 1.1.7 jsrsasign 5.0.13
1226  * @deprecated from 10.0.6. please use {@link ishex}
1227  * @see ishex
1228  * @example
1229  * KJUR.lang.String.isHex("1234") → true
1230  * KJUR.lang.String.isHex("12ab") → true
1231  * KJUR.lang.String.isHex("12AB") → true
1232  * KJUR.lang.String.isHex("12ZY") → false
1233  * KJUR.lang.String.isHex("121") → false -- odd length
1234  */
1235 KJUR.lang.String.isHex = function(s) {
1236     return ishex(s);
1237 };
1238 
1239 /**
1240  * check whether a string is an hexadecimal string or not<br/>
1241  * @name ishex
1242  * @function
1243  * @static
1244  * @param {String} s input string
1245  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1246  * @since base64x 1.1.7 jsrsasign 5.0.13
1247  * @example
1248  * ishex("1234") → true
1249  * ishex("12ab") → true
1250  * ishex("12AB") → true
1251  * ishex("12ZY") → false
1252  * ishex("121") → false -- odd length
1253  */
1254 function ishex(s) {
1255     if (s.length % 2 == 0 &&
1256 	(s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) {
1257 	return true;
1258     } else {
1259 	return false;
1260     }
1261 };
1262 
1263 /**
1264  * check whether a string is a base64 encoded string or not<br/>
1265  * Input string can conclude new lines or space characters.
1266  * @name isBase64
1267  * @memberOf KJUR.lang.String
1268  * @function
1269  * @static
1270  * @param {String} s input string
1271  * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false
1272  * @since base64x 1.1.7 jsrsasign 5.0.13
1273  * @example
1274  * KJUR.lang.String.isBase64("YWE=") → true
1275  * KJUR.lang.String.isBase64("YW_=") → false
1276  * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4
1277  */
1278 KJUR.lang.String.isBase64 = function(s) {
1279     s = s.replace(/\s+/g, "");
1280     if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) {
1281 	return true;
1282     } else {
1283 	return false;
1284     }
1285 };
1286 
1287 /**
1288  * check whether a string is a base64url encoded string or not<br/>
1289  * Input string can conclude new lines or space characters.
1290  * @name isBase64URL
1291  * @memberOf KJUR.lang.String
1292  * @function
1293  * @static
1294  * @param {String} s input string
1295  * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false
1296  * @since base64x 1.1.7 jsrsasign 5.0.13
1297  * @example
1298  * KJUR.lang.String.isBase64URL("YWE") → true
1299  * KJUR.lang.String.isBase64URL("YW-") → true
1300  * KJUR.lang.String.isBase64URL("YW+") → false
1301  */
1302 KJUR.lang.String.isBase64URL = function(s) {
1303     if (s.match(/[+/=]/)) return false;
1304     s = b64utob64(s);
1305     return KJUR.lang.String.isBase64(s);
1306 };
1307 
1308 
1309 /**
1310  * check whether a string is a base64url encoded string and dot or not<br/>
1311  * Input string can conclude new lines or space characters.
1312  * @name isBase64URLDot
1313  * @function
1314  * @static
1315  * @param {String} s input string
1316  * @return {Boolean} true if a string "s" is a base64url encoded string and dot otherwise false
1317  * @since base64x 1.1.30 jsrsasign 10.5.25
1318  * @example
1319  * isBase64URLDot("YWE") → true
1320  * isBase64URLDot("YWE.YWE.YWE") → true
1321  * isBase64URLDot("YW-") → true
1322  * isBase64URLDot("YW+") → false
1323  */
1324 function isBase64URLDot(s) {
1325     if (s.match(/^[0-9A-Za-z-_.]+$/)) return true;
1326     return false;
1327 }
1328 
1329 /**
1330  * check whether a string is a string of integer array or not<br/>
1331  * Input string can conclude new lines or space characters.
1332  * @name isIntegerArray
1333  * @memberOf KJUR.lang.String
1334  * @function
1335  * @static
1336  * @param {String} s input string
1337  * @return {Boolean} true if a string "s" is a string of integer array otherwise false
1338  * @since base64x 1.1.7 jsrsasign 5.0.13
1339  * @example
1340  * KJUR.lang.String.isIntegerArray("[1,2,3]") → true
1341  * KJUR.lang.String.isIntegerArray("  [1, 2, 3  ] ") → true
1342  * KJUR.lang.String.isIntegerArray("[a,2]") → false
1343  */
1344 KJUR.lang.String.isIntegerArray = function(s) {
1345     s = s.replace(/\s+/g, "");
1346     if (s.match(/^\[[0-9,]+\]$/)) {
1347 	return true;
1348     } else {
1349 	return false;
1350     }
1351 };
1352 
1353 /**
1354  * check whether a string consists of PrintableString characters<br/>
1355  * @name isPrintable
1356  * @memberOf KJUR.lang.String
1357  * @function
1358  * @static
1359  * @param {String} s input string
1360  * @return {Boolean} true if a string "s" consists of PrintableString characters
1361  * @since jsrsasign 9.0.0 base64x 1.1.16
1362  * A PrintableString consists of following characters
1363  * <pre>
1364  * 0-9A-Za-z '()+,-./:=?
1365  * </pre>
1366  * This method returns false when other characters than above.
1367  * Otherwise it returns true.
1368  * @example
1369  * KJUR.lang.String.isPrintable("abc") → true
1370  * KJUR.lang.String.isPrintable("abc@") → false
1371  * KJUR.lang.String.isPrintable("あいう") → false
1372  */
1373 KJUR.lang.String.isPrintable = function(s) {
1374     if (s.match(/^[0-9A-Za-z '()+,-./:=?]*$/) !== null) return true;
1375     return false;
1376 };
1377 
1378 /**
1379  * check whether a string consists of IAString characters<br/>
1380  * @name isIA5
1381  * @memberOf KJUR.lang.String
1382  * @function
1383  * @static
1384  * @param {String} s input string
1385  * @return {Boolean} true if a string "s" consists of IA5String characters
1386  * @since jsrsasign 9.0.0 base64x 1.1.16
1387  * A IA5String consists of following characters
1388  * <pre>
1389  * %x00-21/%x23-7F (i.e. ASCII characters excludes double quote(%x22)
1390  * </pre>
1391  * This method returns false when other characters than above.
1392  * Otherwise it returns true.
1393  * @example
1394  * KJUR.lang.String.isIA5("abc") → true
1395  * KJUR.lang.String.isIA5('"abc"') → false
1396  * KJUR.lang.String.isIA5("あいう") → false
1397  */
1398 KJUR.lang.String.isIA5 = function(s) {
1399     if (s.match(/^[\x20-\x21\x23-\x7f]*$/) !== null) return true;
1400     return false;
1401 };
1402 
1403 /**
1404  * check whether a string is RFC 822 mail address<br/>
1405  * @name isMail
1406  * @memberOf KJUR.lang.String
1407  * @function
1408  * @static
1409  * @param {String} s input string
1410  * @return {Boolean} true if a string "s" RFC 822 mail address
1411  * @since jsrsasign 9.0.0 base64x 1.1.16
1412  * This static method will check string s is RFC 822 compliant mail address.
1413  * @example
1414  * KJUR.lang.String.isMail("abc") → false
1415  * KJUR.lang.String.isMail("abc@example") → false
1416  * KJUR.lang.String.isMail("abc@example.com") → true
1417  */
1418 KJUR.lang.String.isMail = function(s) {
1419     if (s.match(/^[A-Za-z0-9]{1}[A-Za-z0-9_.-]*@{1}[A-Za-z0-9_.-]{1,}\.[A-Za-z0-9]{1,}$/) !== null) return true;
1420     return false;
1421 };
1422 
1423 // ==== others ================================
1424 
1425 /**
1426  * canonicalize hexadecimal string of positive integer<br/>
1427  * @name hextoposhex
1428  * @function
1429  * @param {String} s hexadecimal string 
1430  * @return {String} canonicalized hexadecimal string of positive integer
1431  * @since base64x 1.1.10 jsrsasign 7.1.4
1432  * @description
1433  * This method canonicalize a hexadecimal string of positive integer
1434  * for two's complement representation.
1435  * Canonicalized hexadecimal string of positive integer will be:
1436  * <ul>
1437  * <li>Its length is always even.</li>
1438  * <li>If odd length it will be padded with leading zero.<li>
1439  * <li>If it is even length and its first character is "8" or greater,
1440  * it will be padded with "00" to make it positive integer.</li>
1441  * </ul>
1442  * @example
1443  * hextoposhex("abcd") → "00abcd"
1444  * hextoposhex("1234") → "1234"
1445  * hextoposhex("12345") → "012345"
1446  */
1447 function hextoposhex(s) {
1448     if (s.length % 2 == 1) return "0" + s;
1449     if (s.substr(0, 1) > "7") return "00" + s;
1450     return s;
1451 }
1452 
1453 /**
1454  * convert string of integer array to hexadecimal string.<br/>
1455  * @name intarystrtohex
1456  * @function
1457  * @param {String} s string of integer array
1458  * @return {String} hexadecimal string
1459  * @since base64x 1.1.6 jsrsasign 5.0.2
1460  * @throws "malformed integer array string: *" for wrong input
1461  * @description
1462  * This function converts a string of JavaScript integer array to
1463  * a hexadecimal string. Each integer value shall be in a range 
1464  * from 0 to 255 otherwise it raise exception. Input string can
1465  * have extra space or newline string so that they will be ignored.
1466  * 
1467  * @example
1468  * intarystrtohex(" [123, 34, 101, 34, 58] ")
1469  * → 7b2265223a (i.e. '{"e":' as string)
1470  */
1471 function intarystrtohex(s) {
1472   s = s.replace(/^\s*\[\s*/, '');
1473   s = s.replace(/\s*\]\s*$/, '');
1474   s = s.replace(/\s*/g, '');
1475   try {
1476     var hex = s.split(/,/).map(function(element, index, array) {
1477       var i = parseInt(element);
1478       if (i < 0 || 255 < i) throw "integer not in range 0-255";
1479       var hI = ("00" + i.toString(16)).slice(-2);
1480       return hI;
1481     }).join('');
1482     return hex;
1483   } catch(ex) {
1484     throw "malformed integer array string: " + ex;
1485   }
1486 }
1487 
1488 /**
1489  * find index of string where two string differs
1490  * @name strdiffidx
1491  * @function
1492  * @param {String} s1 string to compare
1493  * @param {String} s2 string to compare
1494  * @return {Number} string index of where character differs. Return -1 if same.
1495  * @since jsrsasign 4.9.0 base64x 1.1.5
1496  * @example
1497  * strdiffidx("abcdefg", "abcd4fg") -> 4
1498  * strdiffidx("abcdefg", "abcdefg") -> -1
1499  * strdiffidx("abcdefg", "abcdef") -> 6
1500  * strdiffidx("abcdefgh", "abcdef") -> 6
1501  */
1502 var strdiffidx = function(s1, s2) {
1503     var n = s1.length;
1504     if (s1.length > s2.length) n = s2.length;
1505     for (var i = 0; i < n; i++) {
1506 	if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i;
1507     }
1508     if (s1.length != s2.length) return n;
1509     return -1; // same
1510 };
1511 
1512 // ==== hex / oid =================================
1513 
1514 /**
1515  * get hexadecimal value of object identifier from dot noted oid value
1516  * @name oidtohex
1517  * @function
1518  * @param {String} oidString dot noted string of object identifier
1519  * @return {String} hexadecimal value of object identifier
1520  * @since jsrsasign 10.1.0 base64x 1.1.18
1521  * @see hextooid
1522  * @see ASN1HEX.hextooidstr
1523  * @see KJUR.asn1.ASN1Util.oidIntToHex
1524  * @description
1525  * This static method converts from object identifier value string.
1526  * to hexadecimal string representation of it.
1527  * {@link hextooid} is a reverse function of this.
1528  * @example
1529  * oidtohex("2.5.4.6") → "550406"
1530  */
1531 function oidtohex(oidString) {
1532     var itox = function(i) {
1533         var h = i.toString(16);
1534         if (h.length == 1) h = '0' + h;
1535         return h;
1536     };
1537 
1538     var roidtox = function(roid) {
1539         var h = '';
1540         var bi = parseInt(roid, 10);
1541         var b = bi.toString(2);
1542 
1543         var padLen = 7 - b.length % 7;
1544         if (padLen == 7) padLen = 0;
1545         var bPad = '';
1546         for (var i = 0; i < padLen; i++) bPad += '0';
1547         b = bPad + b;
1548         for (var i = 0; i < b.length - 1; i += 7) {
1549             var b8 = b.substr(i, 7);
1550             if (i != b.length - 7) b8 = '1' + b8;
1551             h += itox(parseInt(b8, 2));
1552         }
1553         return h;
1554     };
1555     
1556     try {
1557 	if (! oidString.match(/^[0-9.]+$/)) return null;
1558     
1559 	var h = '';
1560 	var a = oidString.split('.');
1561 	var i0 = parseInt(a[0], 10) * 40 + parseInt(a[1], 10);
1562 	h += itox(i0);
1563 	a.splice(0, 2);
1564 	for (var i = 0; i < a.length; i++) {
1565             h += roidtox(a[i]);
1566 	}
1567 	return h;
1568     } catch(ex) {
1569 	return null;
1570     }
1571 };
1572 
1573 /**
1574  * get oid string from hexadecimal value of object identifier<br/>
1575  * @name hextooid
1576  * @function
1577  * @param {String} h hexadecimal value of object identifier
1578  * @return {String} dot noted string of object identifier (ex. "1.2.3.4")
1579  * @since jsrsasign 10.1.0 base64x 1.1.18
1580  * @see oidtohex
1581  * @see ASN1HEX.hextooidstr
1582  * @see KJUR.asn1.ASN1Util.oidIntToHex
1583  * @description
1584  * This static method converts from hexadecimal object identifier value 
1585  * to dot noted OID value (ex. "1.2.3.4").
1586  * {@link oidtohex} is a reverse function of this.
1587  * @example
1588  * hextooid("550406") → "2.5.4.6"
1589  */
1590 function hextooid(h) {
1591     if (! ishex(h)) return null;
1592     try {
1593 	var a = [];
1594 
1595 	// a[0], a[1]
1596 	var hex0 = h.substr(0, 2);
1597 	var i0 = parseInt(hex0, 16);
1598 	a[0] = new String(Math.floor(i0 / 40));
1599 	a[1] = new String(i0 % 40);
1600 
1601 	// a[2]..a[n]
1602 	var hex1 = h.substr(2);
1603 	var b = [];
1604 	for (var i = 0; i < hex1.length / 2; i++) {
1605 	    b.push(parseInt(hex1.substr(i * 2, 2), 16));
1606 	}
1607 	var c = [];
1608 	var cbin = "";
1609 	for (var i = 0; i < b.length; i++) {
1610             if (b[i] & 0x80) {
1611 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1612             } else {
1613 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1614 		c.push(new String(parseInt(cbin, 2)));
1615 		cbin = "";
1616             }
1617 	}
1618 
1619 	var s = a.join(".");
1620 	if (c.length > 0) s = s + "." + c.join(".");
1621 	return s;
1622     } catch(ex) {
1623 	return null;
1624     }
1625 };
1626 
1627 /**
1628  * string padding<br/>
1629  * @name strpad
1630  * @function
1631  * @param {String} s input string
1632  * @param {Number} len output string length
1633  * @param {String} padchar padding character (default is "0")
1634  * @return {String} padded string
1635  * @since jsrsasign 10.1.0 base64x 1.1.18
1636  * @example
1637  * strpad("1234", 10, "0") → "0000001234"
1638  * strpad("1234", 10, " ") → "      1234"
1639  * strpad("1234", 10)      → "0000001234"
1640  */
1641 var strpad = function(s, len, padchar) {
1642     if (padchar == undefined) padchar = "0";
1643     if (s.length >= len) return s;
1644     return new Array(len - s.length + 1).join(padchar) + s;
1645 };
1646 
1647 // ==== bitstr hex / int =================================
1648 
1649 /**
1650  * convert from hexadecimal string of ASN.1 BitString value with unused bit to integer value<br/>
1651  * @name bitstrtoint
1652  * @function
1653  * @param {String} h hexadecimal string of ASN.1 BitString value with unused bit
1654  * @return {Number} positive integer value of the BitString
1655  * @since jsrsasign 10.1.3 base64x 1.1.19
1656  * @see inttobitstr
1657  * @see KJUR.asn1.DERBitString
1658  * @see ASN1HEX.getInt
1659  * 
1660  * @description
1661  * This function converts from hexadecimal string of ASN.1 BitString
1662  * value with unused bit to its integer value. <br/>
1663  * When an improper hexadecimal string of BitString value
1664  * is applied, this returns -1.
1665  * 
1666  * @example
1667  * // "03c8" → 0xc8 unusedbit=03 → 11001000b unusedbit=03 → 11001b → 25
1668  * bitstrtoint("03c8") → 25
1669  * // "02fff8" → 0xfff8 unusedbit=02 → 1111111111111000b unusedbit=02
1670  * //   11111111111110b → 16382
1671  * bitstrtoint("02fff8") → 16382
1672  * bitstrtoint("05a0") → 5 (=101b)
1673  * bitstrtoint("ff00") → -1 // for improper BitString value
1674  * bitstrtoint("05a0").toString(2) → "101"
1675  * bitstrtoint("07a080").toString(2) → "101000001"
1676  */
1677 function bitstrtoint(h) {
1678     if (h.length % 2 != 0) return -1; 
1679     h = h.toLowerCase();
1680     if (h.match(/^[0-9a-f]+$/) == null) return -1;
1681     try {
1682 	var hUnusedbit = h.substr(0, 2);
1683 	if (hUnusedbit == "00")
1684 	    return parseInt(h.substr(2), 16);
1685 	var iUnusedbit = parseInt(hUnusedbit, 16);
1686 	if (iUnusedbit > 7) return -1;
1687 	var hValue = h.substr(2);
1688 	var bValue = parseInt(hValue, 16).toString(2);
1689 	if (bValue == "0") bValue = "00000000";
1690 	bValue = bValue.slice(0, 0 - iUnusedbit);
1691 	var iValue = parseInt(bValue, 2);
1692 	if (iValue == NaN) return -1;
1693 	return iValue;
1694     } catch(ex) {
1695 	return -1;
1696     }
1697 };
1698 
1699 /**
1700  * convert from integer value to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1701  * @name inttobitstr
1702  * @function
1703  * @param {Number} n integer value of ASN.1 BitString
1704  * @return {String} hexadecimal string of ASN.1 BitString value with unused bit
1705  * @since jsrsasign 10.1.3 base64x 1.1.19
1706  * @see bitstrtoint
1707  * @see KJUR.asn1.DERBitString
1708  * @see ASN1HEX.getInt
1709  * 
1710  * @description
1711  * This function converts from an integer value to 
1712  * hexadecimal string of ASN.1 BitString value
1713  * with unused bit. <br/>
1714  * When "n" is not non-negative number, this returns null
1715  * 
1716  * @example
1717  * // 25 → 11001b → 11001000b unusedbit=03 → 0xc8 unusedbit=03 → "03c8"
1718  * inttobitstr(25) → "03c8"
1719  * inttobitstr(-3) → null
1720  * inttobitstr("abc") → null
1721  * inttobitstr(parseInt("11001", 2)) → "03c8"
1722  * inttobitstr(parseInt("101", 2)) → "05a0"
1723  * inttobitstr(parseInt("101000001", 2)) → "07a080"
1724  */
1725 function inttobitstr(n) {
1726     if (typeof n != "number") return null;
1727     if (n < 0) return null;
1728     var bValue = Number(n).toString(2);
1729     var iUnusedbit = 8 - bValue.length % 8;
1730     if (iUnusedbit == 8) iUnusedbit = 0;
1731     bValue = bValue + strpad("", iUnusedbit, "0");
1732     var hValue = parseInt(bValue, 2).toString(16);
1733     if (hValue.length % 2 == 1) hValue = "0" + hValue;
1734     var hUnusedbit = "0" + iUnusedbit;
1735     return hUnusedbit + hValue;
1736 };
1737 
1738 // ==== bitstr hex / binary string =======================
1739 
1740 /**
1741  * convert from hexadecimal string of ASN.1 BitString value with unused bit to binary string<br/>
1742  * @name bitstrtobinstr
1743  * @function
1744  * @param {string} h hexadecimal string of ASN.1 BitString value with unused bit
1745  * @return {string} binary string
1746  * @since jsrsasign 10.5.4 base64x 1.1.21
1747  * @see binstrtobitstr
1748  * @see inttobitstr
1749  * 
1750  * @description
1751  * This function converts from hexadecimal string of ASN.1 BitString
1752  * value with unused bit to its integer value. <br/>
1753  * When an improper hexadecimal string of BitString value
1754  * is applied, this returns null.
1755  * 
1756  * @example
1757  * bitstrtobinstr("05a0") → "101"
1758  * bitstrtobinstr("0520") → "001"
1759  * bitstrtobinstr("07a080") → "101000001"
1760  * bitstrtobinstr(502) → null // non ASN.1 BitString value
1761  * bitstrtobinstr("ff00") → null // for improper BitString value
1762  */
1763 function bitstrtobinstr(h) {
1764     if (typeof h != "string") return null;
1765     if (h.length % 2 != 0) return null;
1766     if (! h.match(/^[0-9a-f]+$/)) return null;
1767     try {
1768 	var unusedBits = parseInt(h.substr(0, 2), 16);
1769 	if (unusedBits < 0 || 7 < unusedBits) return null
1770 
1771 	var value = h.substr(2);
1772 	var bin = "";
1773 	for (var i = 0; i < value.length; i += 2) {
1774 	    var hi = value.substr(i, 2);
1775 	    var bi = parseInt(hi, 16).toString(2);
1776 	    bi = ("0000000" + bi).slice(-8);
1777 	    bin += bi;
1778 	}
1779 	return  bin.substr(0, bin.length - unusedBits);
1780     } catch(ex) {
1781 	return null;
1782     }
1783 }
1784 
1785 /**
1786  * convert from binary string to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1787  * @name binstrtobitstr
1788  * @function
1789  * @param {string} s binary string (ex. "101")
1790  * @return {string} hexadecimal string of ASN.1 BitString value with unused bit
1791  * @since jsrsasign 10.5.4 base64x 1.1.21
1792  * @see bitstrtobinstr
1793  * @see inttobitstr
1794  * @see KJUR.asn1.DERBitString
1795  * 
1796  * @description
1797  * This function converts from an binary string (ex. "101") to 
1798  * hexadecimal string of ASN.1 BitString value
1799  * with unused bit (ex. "05a0"). <br/>
1800  * When "s" is not binary string, this returns null.
1801  * 
1802  * @example
1803  * binstrtobitstr("101") → "05a0"
1804  * binstrtobitstr("001") → "0520"
1805  * binstrtobitstr("11001") → "03c8"
1806  * binstrtobitstr("101000001") → "07a080"
1807  * binstrtobitstr(101) → null // not number
1808  * binstrtobitstr("xyz") → null // not binary string
1809  */
1810 function binstrtobitstr(s) {
1811     if (typeof s != "string") return null;
1812     if (s.match(/^[01]+$/) == null) return null;
1813     try {
1814 	var n = parseInt(s, 2);
1815 	return inttobitstr(n);
1816     } catch(ex) {
1817 	return null;
1818     }
1819 }
1820 
1821 // =======================================================
1822 /**
1823  * convert array of names to bit string<br/>
1824  * @name namearraytobinstr
1825  * @function
1826  * @param {array} namearray array of name string
1827  * @param {object} namedb associative array of name and value
1828  * @return {string} binary string (ex. "110001")
1829  * @since jsrsasign 10.5.21 base64x 1.1.27
1830  * @see KJUR.asn1.x509.KeyUsage
1831  * @see KJUR.asn1.tsp.PKIFailureInfo
1832  * 
1833  * @description
1834  * This function converts from an array of names to
1835  * a binary string. DB value bit will be set.
1836  * Note that ordering of namearray items
1837  * will be ignored.
1838  *
1839  * @example
1840  * db = { a: 0, b: 3, c: 8, d: 9, e: 17, f: 19 };
1841  * namearraytobinstr(['a', 'c', 'd'], db) &rarr: '1000000011'
1842  * namearraytobinstr(['c', 'b'], db) &rarr: '000100001'
1843  */
1844 function namearraytobinstr (namearray, namedb) {
1845     var d = 0;
1846     for (var i = 0; i < namearray.length; i++) {
1847 	d |= 1 << namedb[namearray[i]];
1848     }
1849 
1850     var s = d.toString(2);
1851     var r = "";
1852     for (var i = s.length - 1; i >=0; i--) {
1853 	r += s[i];
1854     }
1855     return r;
1856 }
1857 
1858 // =======================================================
1859 /**
1860  * set class inheritance<br/>
1861  * @name extendClass
1862  * @function
1863  * @param {Function} subClass sub class to set inheritance
1864  * @param {Function} superClass super class to inherit
1865  * @since jsrsasign 10.3.0 base64x 1.1.21
1866  *
1867  * @description
1868  * This function extends a class and set an inheritance
1869  * for member variables and methods.
1870  *
1871  * @example
1872  * var Animal = function() {
1873  *   this.hello = function(){console.log("Hello")};
1874  *   this.name="Ani";
1875  * };
1876  * var Dog = function() {
1877  *   Dog.superclass.constructor.call(this);
1878  *   this.vow = function(){console.log("Vow wow")};
1879  *   this.tail=true;
1880  * };
1881  * extendClass(Dog, Animal);
1882  */
1883 function extendClass(subClass, superClass) {
1884     var F = function() {};
1885     F.prototype = superClass.prototype;
1886     subClass.prototype = new F();
1887     subClass.prototype.constructor = subClass;
1888     subClass.superclass = superClass.prototype;
1889      
1890     if (superClass.prototype.constructor == Object.prototype.constructor) {
1891         superClass.prototype.constructor = superClass;
1892     }
1893 };
1894 
1895