1 /* base64x-1.1.20 (c) 2012-2021 Kenji Urushima | kjur.github.com/jsrsasign/license
  2  */
  3 /*
  4  * base64x.js - Base64url and supplementary functions for Tom Wu's base64.js library
  5  *
  6  * Copyright (c) 2012-2021 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.1.13 base64x 1.1.20 (2021-Mar-07)
 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));
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   return decodeURIComponent(hextouricmp(s));
340 }
341 
342 /**
343  * convert a hexadecimal encoded string to raw string including non printable characters.<br/>
344  * @name hextorstr
345  * @function
346  * @param {String} s hexadecimal encoded string
347  * @return {String} raw string
348  * @since 1.1.2
349  * @example
350  * hextorstr("610061") → "a\x00a"
351  */
352 function hextorstr(sHex) {
353     var s = "";
354     for (var i = 0; i < sHex.length - 1; i += 2) {
355         s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16));
356     }
357     return s;
358 }
359 
360 /**
361  * convert a raw string including non printable characters to hexadecimal encoded string.<br/>
362  * @name rstrtohex
363  * @function
364  * @param {String} s raw string
365  * @return {String} hexadecimal encoded string
366  * @since 1.1.2
367  * @example
368  * rstrtohex("a\x00a") → "610061"
369  */
370 function rstrtohex(s) {
371     var result = "";
372     for (var i = 0; i < s.length; i++) {
373         result += ("0" + s.charCodeAt(i).toString(16)).slice(-2);
374     }
375     return result;
376 }
377 
378 // ==== hex / b64nl =======================================
379 
380 /**
381  * convert a hexadecimal string to Base64 encoded string<br/>
382  * @name hextob64
383  * @function
384  * @param {String} s hexadecimal string
385  * @return {String} resulted Base64 encoded string
386  * @since base64x 1.1.3
387  * @description
388  * This function converts from a hexadecimal string to Base64 encoded
389  * string without new lines.
390  * @example
391  * hextob64("616161") → "YWFh"
392  */
393 function hextob64(s) {
394     return hex2b64(s);
395 }
396 
397 /**
398  * convert a hexadecimal string to Base64 encoded string with new lines<br/>
399  * @name hextob64nl
400  * @function
401  * @param {String} s hexadecimal string
402  * @return {String} resulted Base64 encoded string with new lines
403  * @since base64x 1.1.3
404  * @description
405  * This function converts from a hexadecimal string to Base64 encoded
406  * string with new lines for each 64 characters. This is useful for
407  * PEM encoded file.
408  * @example
409  * hextob64nl("123456789012345678901234567890123456789012345678901234567890")
410  * →
411  * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line
412  * OTAxMjM0NTY3ODkwCg==
413  */
414 function hextob64nl(s) {
415     var b64 = hextob64(s);
416     var b64nl = b64.replace(/(.{64})/g, "$1\r\n");
417     b64nl = b64nl.replace(/\r\n$/, '');
418     return b64nl;
419 }
420 
421 /**
422  * convert a Base64 encoded string with new lines to a hexadecimal string<br/>
423  * @name b64nltohex
424  * @function
425  * @param {String} s Base64 encoded string with new lines
426  * @return {String} hexadecimal string
427  * @since base64x 1.1.3
428  * @description
429  * This function converts from a Base64 encoded
430  * string with new lines to a hexadecimal string.
431  * This is useful to handle PEM encoded file.
432  * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=)
433  * including new line.
434  * @example
435  * hextob64nl(
436  * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" +
437  * "OTAxMjM0NTY3ODkwCg==\r\n")
438  * →
439  * "123456789012345678901234567890123456789012345678901234567890"
440  */
441 function b64nltohex(s) {
442     var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, '');
443     var hex = b64tohex(b64);
444     return hex;
445 } 
446 
447 // ==== hex / pem =========================================
448 
449 /**
450  * get PEM string from hexadecimal data and header string
451  * @name hextopem
452  * @function
453  * @param {String} dataHex hexadecimal string of PEM body
454  * @param {String} pemHeader PEM header string (ex. 'RSA PRIVATE KEY')
455  * @return {String} PEM formatted string of input data
456  * @since jsrasign 7.2.1 base64x 1.1.12
457  * @description
458  * This function converts a hexadecimal string to a PEM string with
459  * a specified header. Its line break will be CRLF("\r\n").
460  * @example
461  * hextopem('616161', 'RSA PRIVATE KEY') →
462  * -----BEGIN PRIVATE KEY-----
463  * YWFh
464  * -----END PRIVATE KEY-----
465  */
466 function hextopem(dataHex, pemHeader) {
467     var pemBody = hextob64nl(dataHex);
468     return "-----BEGIN " + pemHeader + "-----\r\n" + 
469         pemBody + 
470         "\r\n-----END " + pemHeader + "-----\r\n";
471 }
472 
473 /**
474  * get hexacedimal string from PEM format data<br/>
475  * @name pemtohex
476  * @function
477  * @param {String} s PEM formatted string
478  * @param {String} sHead PEM header string without BEGIN/END(OPTION)
479  * @return {String} hexadecimal string data of PEM contents
480  * @since jsrsasign 7.2.1 base64x 1.1.12
481  * @description
482  * This static method gets a hexacedimal string of contents 
483  * from PEM format data. You can explicitly specify PEM header 
484  * by sHead argument. 
485  * Any space characters such as white space or new line
486  * will be omitted.<br/>
487  * NOTE: Now {@link KEYUTIL.getHexFromPEM} and {@link X509.pemToHex}
488  * have been deprecated since jsrsasign 7.2.1. 
489  * Please use this method instead.
490  * NOTE2: From jsrsasign 8.0.14 this can process multi
491  * "BEGIN...END" section such as "EC PRIVATE KEY" with "EC PARAMETERS".
492  * @example
493  * pemtohex("-----BEGIN PUBLIC KEY...") → "3082..."
494  * pemtohex("-----BEGIN CERTIFICATE...", "CERTIFICATE") → "3082..."
495  * pemtohex(" \r\n-----BEGIN DSA PRIVATE KEY...") → "3082..."
496  * pemtohex("-----BEGIN EC PARAMETERS...----BEGIN EC PRIVATE KEY...." → "3082..."
497  */
498 function pemtohex(s, sHead) {
499     if (s.indexOf("-----BEGIN ") == -1)
500         throw "can't find PEM header: " + sHead;
501 
502     if (sHead !== undefined) {
503         s = s.replace(new RegExp('^[^]*-----BEGIN ' + sHead + '-----'), '');
504         s = s.replace(new RegExp('-----END ' + sHead + '-----[^]*$'), '');
505     } else {
506         s = s.replace(/^[^]*-----BEGIN [^-]+-----/, '');
507         s = s.replace(/-----END [^-]+-----[^]*$/, '');
508     }
509     return b64nltohex(s);
510 }
511 
512 // ==== hex / ArrayBuffer =================================
513 
514 /**
515  * convert a hexadecimal string to an ArrayBuffer<br/>
516  * @name hextoArrayBuffer
517  * @function
518  * @param {String} hex hexadecimal string
519  * @return {ArrayBuffer} ArrayBuffer
520  * @since jsrsasign 6.1.4 base64x 1.1.8
521  * @description
522  * This function converts from a hexadecimal string to an ArrayBuffer.
523  * @example
524  * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1]
525  */
526 function hextoArrayBuffer(hex) {
527     if (hex.length % 2 != 0) throw "input is not even length";
528     if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal";
529 
530     var buffer = new ArrayBuffer(hex.length / 2);
531     var view = new DataView(buffer);
532 
533     for (var i = 0; i < hex.length / 2; i++) {
534 	view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16));
535     }
536 
537     return buffer;
538 }
539 
540 // ==== ArrayBuffer / hex =================================
541 
542 /**
543  * convert an ArrayBuffer to a hexadecimal string<br/>
544  * @name ArrayBuffertohex
545  * @function
546  * @param {ArrayBuffer} buffer ArrayBuffer
547  * @return {String} hexadecimal string
548  * @since jsrsasign 6.1.4 base64x 1.1.8
549  * @description
550  * This function converts from an ArrayBuffer to a hexadecimal string.
551  * @example
552  * var buffer = new ArrayBuffer(3);
553  * var view = new DataView(buffer);
554  * view.setUint8(0, 0xfa);
555  * view.setUint8(1, 0xfb);
556  * view.setUint8(2, 0x01);
557  * ArrayBuffertohex(buffer) → "fafb01"
558  */
559 function ArrayBuffertohex(buffer) {
560     var hex = "";
561     var view = new DataView(buffer);
562 
563     for (var i = 0; i < buffer.byteLength; i++) {
564 	hex += ("00" + view.getUint8(i).toString(16)).slice(-2);
565     }
566 
567     return hex;
568 }
569 
570 // ==== zulu / int =================================
571 /**
572  * GeneralizedTime or UTCTime string to milliseconds from Unix origin<br>
573  * @name zulutomsec
574  * @function
575  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
576  * @return {Number} milliseconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
577  * @since jsrsasign 7.1.3 base64x 1.1.9
578  * @description
579  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
580  * UTCTime string (i.e. YYMMDDHHmmSSZ) to milliseconds from Unix origin time
581  * (i.e. Jan 1 1970 0:00:00 UTC). 
582  * Argument string may have fraction of seconds and
583  * its length is one or more digits such as "20170410235959.1234567Z".
584  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
585  * If year "YY" is equal or greater than 50 then it is 19YY.
586  * @example
587  * zulutomsec(  "071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
588  * zulutomsec(  "071231235959.1Z")     → 1199145599100 #Mon, 31 Dec 2007 23:59:59 GMT
589  * zulutomsec(  "071231235959.12345Z") → 1199145599123 #Mon, 31 Dec 2007 23:59:59 GMT
590  * zulutomsec("20071231235959Z")       → 1199145599000 #Mon, 31 Dec 2007 23:59:59 GMT
591  * zulutomsec(  "931231235959Z")       → -410227201000 #Mon, 31 Dec 1956 23:59:59 GMT
592  */
593 function zulutomsec(s) {
594     var year, month, day, hour, min, sec, msec, d;
595     var sYear, sFrac, sMsec, matchResult;
596 
597     matchResult = s.match(/^(\d{2}|\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(|\.\d+)Z$/);
598 
599     if (matchResult) {
600         sYear = matchResult[1];
601 	year = parseInt(sYear);
602         if (sYear.length === 2) {
603 	    if (50 <= year && year < 100) {
604 		year = 1900 + year;
605 	    } else if (0 <= year && year < 50) {
606 		year = 2000 + year;
607 	    }
608 	}
609 	month = parseInt(matchResult[2]) - 1;
610 	day = parseInt(matchResult[3]);
611 	hour = parseInt(matchResult[4]);
612 	min = parseInt(matchResult[5]);
613 	sec = parseInt(matchResult[6]);
614 	msec = 0;
615 
616 	sFrac = matchResult[7];
617 	if (sFrac !== "") {
618 	    sMsec = (sFrac.substr(1) + "00").substr(0, 3); // .12 -> 012
619 	    msec = parseInt(sMsec);
620 	}
621 	return Date.UTC(year, month, day, hour, min, sec, msec);
622     }
623     throw "unsupported zulu format: " + s;
624 }
625 
626 /**
627  * GeneralizedTime or UTCTime string to seconds from Unix origin<br>
628  * @name zulutosec
629  * @function
630  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
631  * @return {Number} seconds from Unix origin time (i.e. Jan 1, 1970 0:00:00 UTC)
632  * @since jsrsasign 7.1.3 base64x 1.1.9
633  * @description
634  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
635  * UTCTime string (i.e. YYMMDDHHmmSSZ) to seconds from Unix origin time
636  * (i.e. Jan 1 1970 0:00:00 UTC). Argument string may have fraction of seconds 
637  * however result value will be omitted.
638  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
639  * If year "YY" is equal or greater than 50 then it is 19YY.
640  * @example
641  * zulutosec(  "071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
642  * zulutosec(  "071231235959.1Z")     → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
643  * zulutosec("20071231235959Z")       → 1199145599 #Mon, 31 Dec 2007 23:59:59 GMT
644  */
645 function zulutosec(s) {
646     var msec = zulutomsec(s);
647     return ~~(msec / 1000);
648 }
649 
650 // ==== zulu / Date =================================
651 
652 /**
653  * GeneralizedTime or UTCTime string to Date object<br>
654  * @name zulutodate
655  * @function
656  * @param {String} s GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
657  * @return {Date} Date object for specified time
658  * @since jsrsasign 7.1.3 base64x 1.1.9
659  * @description
660  * This function converts from GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
661  * UTCTime string (i.e. YYMMDDHHmmSSZ) to Date object.
662  * Argument string may have fraction of seconds and
663  * its length is one or more digits such as "20170410235959.1234567Z".
664  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
665  * If year "YY" is equal or greater than 50 then it is 19YY.
666  * @example
667  * zulutodate(  "071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
668  * zulutodate(  "071231235959.1Z").toUTCString() → "Mon, 31 Dec 2007 23:59:59 GMT"
669  * zulutodate("20071231235959Z").toUTCString()   → "Mon, 31 Dec 2007 23:59:59 GMT"
670  * zulutodate(  "071231235959.34").getMilliseconds() → 340
671  */
672 function zulutodate(s) {
673     return new Date(zulutomsec(s));
674 }
675 
676 // ==== Date / zulu =================================
677 
678 /**
679  * Date object to zulu time string<br>
680  * @name datetozulu
681  * @function
682  * @param {Date} d Date object for specified time
683  * @param {Boolean} flagUTCTime if this is true year will be YY otherwise YYYY
684  * @param {Boolean} flagMilli if this is true result concludes milliseconds
685  * @return {String} GeneralizedTime or UTCTime string (ex. 20170412235959.384Z)
686  * @since jsrsasign 7.2.0 base64x 1.1.11
687  * @description
688  * This function converts from Date object to GeneralizedTime string (i.e. YYYYMMDDHHmmSSZ) or
689  * UTCTime string (i.e. YYMMDDHHmmSSZ).
690  * As for UTCTime, if year "YY" is equal or less than 49 then it is 20YY.
691  * If year "YY" is equal or greater than 50 then it is 19YY.
692  * If flagMilli is true its result concludes milliseconds such like
693  * "20170520235959.42Z". 
694  * @example
695  * d = new Date(Date.UTC(2017,4,20,23,59,59,670));
696  * datetozulu(d) → "20170520235959Z"
697  * datetozulu(d, true) → "170520235959Z"
698  * datetozulu(d, false, true) → "20170520235959.67Z"
699  */
700 function datetozulu(d, flagUTCTime, flagMilli) {
701     var s;
702     var year = d.getUTCFullYear();
703     if (flagUTCTime) {
704 	if (year < 1950 || 2049 < year) 
705 	    throw "not proper year for UTCTime: " + year;
706 	s = ("" + year).slice(-2);
707     } else {
708 	s = ("000" + year).slice(-4);
709     }
710     s += ("0" + (d.getUTCMonth() + 1)).slice(-2);
711     s += ("0" + d.getUTCDate()).slice(-2);
712     s += ("0" + d.getUTCHours()).slice(-2);
713     s += ("0" + d.getUTCMinutes()).slice(-2);
714     s += ("0" + d.getUTCSeconds()).slice(-2);
715     if (flagMilli) {
716 	var milli = d.getUTCMilliseconds();
717 	if (milli !== 0) {
718 	    milli = ("00" + milli).slice(-3);
719 	    milli = milli.replace(/0+$/g, "");
720 	    s += "." + milli;
721 	}
722     }
723     s += "Z";
724     return s;
725 }
726 
727 // ==== URIComponent / hex ================================
728 /**
729  * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/>
730  * @name uricmptohex
731  * @function
732  * @param {String} s URIComponent string such like "%67%68"
733  * @return {String} hexadecimal string
734  * @since 1.1
735  */
736 function uricmptohex(s) {
737   return s.replace(/%/g, "");
738 }
739 
740 /**
741  * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/>
742  * @name hextouricmp
743  * @function
744  * @param {String} s hexadecimal string
745  * @return {String} URIComponent string such like "%67%68"
746  * @since 1.1
747  */
748 function hextouricmp(s) {
749   return s.replace(/(..)/g, "%$1");
750 }
751 
752 // ==== hex / ipv6 =================================
753 
754 /**
755  * convert any IPv6 address to a 16 byte hexadecimal string
756  * @function
757  * @param s string of IPv6 address
758  * @return {String} 16 byte hexadecimal string of IPv6 address
759  * @description
760  * This function converts any IPv6 address representation string
761  * to a 16 byte hexadecimal string of address.
762  * @example
763  * 
764  */
765 function ipv6tohex(s) {
766   var msgMalformedAddress = "malformed IPv6 address";
767   if (! s.match(/^[0-9A-Fa-f:]+$/))
768     throw msgMalformedAddress;
769 
770   // 1. downcase
771   s = s.toLowerCase();
772 
773   // 2. expand ::
774   var num_colon = s.split(':').length - 1;
775   if (num_colon < 2) throw msgMalformedAddress;
776   var colon_replacer = ':'.repeat(7 - num_colon + 2);
777   s = s.replace('::', colon_replacer);
778 
779   // 3. fill zero
780   var a = s.split(':');
781   if (a.length != 8) throw msgMalformedAddress;
782   for (var i = 0; i < 8; i++) {
783     a[i] = ("0000" + a[i]).slice(-4);
784   }
785   return a.join('');
786 }
787 
788 /**
789  * convert a 16 byte hexadecimal string to RFC 5952 canonicalized IPv6 address<br/>
790  * @name hextoipv6
791  * @function
792  * @param {String} s hexadecimal string of 16 byte IPv6 address
793  * @return {String} IPv6 address string canonicalized by RFC 5952
794  * @since jsrsasign 8.0.10 base64x 1.1.13
795  * @description
796  * This function converts a 16 byte hexadecimal string to 
797  * <a href="https://tools.ietf.org/html/rfc5952">RFC 5952</a>
798  * canonicalized IPv6 address string.
799  * @example
800  * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4"
801  * hextoip("871020010db8000000000000000000") &rarr raise exception
802  * hextoip("xyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyzxyz") &rarr raise exception
803  */
804 function hextoipv6(s) {
805   if (! s.match(/^[0-9A-Fa-f]{32}$/))
806     throw "malformed IPv6 address octet";
807 
808   // 1. downcase
809   s = s.toLowerCase();
810 
811   // 2. split 4
812   var a = s.match(/.{1,4}/g);
813 
814   // 3. trim leading 0
815   for (var i = 0; i < 8; i++) {
816     a[i] = a[i].replace(/^0+/, "");
817     if (a[i] == '') a[i] = '0';
818   }
819   s = ":" + a.join(":") + ":";
820 
821   // 4. find shrinkables :0:0:...
822   var aZero = s.match(/:(0:){2,}/g);
823 
824   // 5. no shrinkable
825   if (aZero === null) return s.slice(1, -1);
826 
827   // 6. find max length :0:0:...
828   var item = '';
829   for (var i = 0; i < aZero.length; i++) {
830     if (aZero[i].length > item.length) item = aZero[i];
831   }
832 
833   // 7. shrink
834   s = s.replace(item, '::');
835   return s.slice(1, -1);
836 }
837 
838 // ==== hex / ip =================================
839 
840 /**
841  * convert a hexadecimal string to IP addresss<br/>
842  * @name hextoip
843  * @function
844  * @param {String} s hexadecimal string of IP address
845  * @return {String} IP address string
846  * @since jsrsasign 8.0.10 base64x 1.1.13
847  * @description
848  * This function converts a hexadecimal string of IPv4 or 
849  * IPv6 address to IPv4 or IPv6 address string.
850  * If byte length is not 4 nor 16, this returns a
851  * hexadecimal string without conversion.
852  * @see {@link hextoipv6}
853  * @example
854  * hextoip("c0a80101") &rarr "192.168.1.1"
855  * hextoip("871020010db8000000000000000000000004") &rarr "2001:db8::4"
856  * hextoip("c0a801010203") &rarr "c0a801010203" // 6 bytes
857  * hextoip("zzz")) &rarr raise exception because of not hexadecimal
858  */
859 function hextoip(s) {
860   var malformedMsg = "malformed hex value";
861   if (! s.match(/^([0-9A-Fa-f][0-9A-Fa-f]){1,}$/))
862     throw malformedMsg;
863   if (s.length == 8) { // ipv4
864     var ip;
865     try {
866       ip = parseInt(s.substr(0, 2), 16) + "." +
867            parseInt(s.substr(2, 2), 16) + "." +
868            parseInt(s.substr(4, 2), 16) + "." +
869            parseInt(s.substr(6, 2), 16);
870       return ip;
871     } catch (ex) {
872       throw malformedMsg;
873     }
874   } else if (s.length == 32) {
875     return hextoipv6(s);
876   } else {
877     return s;
878   }
879 }
880 
881 /**
882  * convert IPv4/v6 addresss to a hexadecimal string<br/>
883  * @name iptohex
884  * @function
885  * @param {String} s IPv4/v6 address string
886  * @return {String} hexadecimal string of IP address
887  * @since jsrsasign 8.0.12 base64x 1.1.14
888  * @description
889  * This function converts IPv4 or IPv6 address string to
890  * a hexadecimal string of IPv4 or IPv6 address.
891  * @example
892  * iptohex("192.168.1.1") &rarr "c0a80101"
893  * iptohex("2001:db8::4") &rarr "871020010db8000000000000000000000004"
894  * iptohex("zzz")) &rarr raise exception
895  */
896 function iptohex(s) {
897   var malformedMsg = "malformed IP address";
898   s = s.toLowerCase(s);
899 
900   if (s.match(/^[0-9.]+$/)) {
901     var a = s.split(".");
902     if (a.length !== 4) throw malformedMsg;
903     var hex = "";
904     try {
905       for (var i = 0; i < 4; i++) {
906         var d = parseInt(a[i]);
907         hex += ("0" + d.toString(16)).slice(-2);
908       }
909       return hex;
910     } catch(ex) {
911       throw malformedMsg;
912     }
913   } else if (s.match(/^[0-9a-f:]+$/) && s.indexOf(":") !== -1) {
914     return ipv6tohex(s);
915   } else {
916     throw malformedMsg;
917   }
918 }
919 
920 // ==== ucs2hex / utf8 ==============================
921 
922 /**
923  * convert UCS-2 hexadecimal stirng to UTF-8 string<br/>
924  * @name ucs2hextoutf8
925  * @function
926  * @param {String} s hexadecimal string of UCS-2 string (ex. "0066")
927  * @return {String} UTF-8 string
928  * @since jsrsasign 10.1.13 base64x 1.1.20
929  * @description
930  * This function converts hexadecimal value of UCS-2 string to 
931  * UTF-8 string.
932  * @example
933  * ucs2hextoutf8("006600fc0072") &rarr "für"
934  */
935 /*
936 See: http://nomenclator.la.coocan.jp/unicode/ucs_utf.htm
937 UCS-2 to UTF-8
938 UCS-2 code point | UCS-2 bytes       | UTF-8 bytes
939 U+0000 .. U+007F | 00000000-0xxxxxxx | 0xxxxxxx (1 byte)
940 U+0080 .. U+07FF | 00000xxx-xxyyyyyy | 110xxxxx 10yyyyyy (2 byte)
941 U+0800 .. U+FFFF | xxxxyyyy-yyzzzzzz | 1110xxxx 10yyyyyy 10zzzzzz (3 byte)
942  */
943 function ucs2hextoutf8(s) {
944     function _conv(s) {
945 	var i1 = parseInt(s.substr(0, 2), 16);
946 	var i2 = parseInt(s.substr(2), 16);
947 	if (i1 == 0 & i2 < 0x80) { // 1 byte
948 	    return String.fromCharCode(i2);
949 	}
950 	if (i1 < 8) { // 2 bytes
951 	    var u1 = 0xc0 | ((i1 & 0x07) << 3) | ((i2 & 0xc0) >> 6);
952 	    var u2 = 0x80 | (i2 & 0x3f);
953 	    return hextoutf8(u1.toString(16) + u2.toString(16));
954 	}
955 	// 3 bytes
956 	var u1 = 0xe0 | ((i1 & 0xf0) >> 4);
957 	var u2 = 0x80 | ((i1 & 0x0f) << 2) | ((i2 & 0xc0) >> 6);
958 	var u3 = 0x80 | (i2 & 0x3f);
959 	return hextoutf8(u1.toString(16) + u2.toString(16) + u3.toString(16));
960     }
961     var a = s.match(/.{4}/g);
962     var a2 = a.map(_conv);
963     return a2.join("");
964 }
965 
966 // ==== URIComponent ================================
967 /**
968  * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/>
969  * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not
970  * converted to "%xx" format by builtin 'encodeURIComponent()' function.
971  * However this 'encodeURIComponentAll()' function will convert 
972  * all of characters into "%xx" format.
973  * @name encodeURIComponentAll
974  * @function
975  * @param {String} s hexadecimal string
976  * @return {String} URIComponent string such like "%67%68"
977  * @since 1.1
978  */
979 function encodeURIComponentAll(u8) {
980   var s = encodeURIComponent(u8);
981   var s2 = "";
982   for (var i = 0; i < s.length; i++) {
983     if (s[i] == "%") {
984       s2 = s2 + s.substr(i, 3);
985       i = i + 2;
986     } else {
987       s2 = s2 + "%" + stohex(s[i]);
988     }
989   }
990   return s2;
991 }
992 
993 // ==== new lines ================================
994 /**
995  * convert all DOS new line("\r\n") to UNIX new line("\n") in 
996  * a String "s".
997  * @name newline_toUnix
998  * @function
999  * @param {String} s string 
1000  * @return {String} converted string
1001  */
1002 function newline_toUnix(s) {
1003     s = s.replace(/\r\n/mg, "\n");
1004     return s;
1005 }
1006 
1007 /**
1008  * convert all UNIX new line("\r\n") to DOS new line("\n") in 
1009  * a String "s".
1010  * @name newline_toDos
1011  * @function
1012  * @param {String} s string 
1013  * @return {String} converted string
1014  */
1015 function newline_toDos(s) {
1016     s = s.replace(/\r\n/mg, "\n");
1017     s = s.replace(/\n/mg, "\r\n");
1018     return s;
1019 }
1020 
1021 // ==== string type checker ===================
1022 
1023 /**
1024  * check whether a string is an integer string or not<br/>
1025  * @name isInteger
1026  * @memberOf KJUR.lang.String
1027  * @function
1028  * @static
1029  * @param {String} s input string
1030  * @return {Boolean} true if a string "s" is an integer string otherwise false
1031  * @since base64x 1.1.7 jsrsasign 5.0.13
1032  * @example
1033  * KJUR.lang.String.isInteger("12345") → true
1034  * KJUR.lang.String.isInteger("123ab") → false
1035  */
1036 KJUR.lang.String.isInteger = function(s) {
1037     if (s.match(/^[0-9]+$/)) {
1038 	return true;
1039     } else if (s.match(/^-[0-9]+$/)) {
1040 	return true;
1041     } else {
1042 	return false;
1043     }
1044 };
1045 
1046 /**
1047  * check whether a string is an hexadecimal string or not (DEPRECATED)<br/>
1048  * @name isHex
1049  * @memberOf KJUR.lang.String
1050  * @function
1051  * @static
1052  * @param {String} s input string
1053  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1054  * @since base64x 1.1.7 jsrsasign 5.0.13
1055  * @deprecated from 10.0.6. please use {@link ishex}
1056  * @see ishex
1057  * @example
1058  * KJUR.lang.String.isHex("1234") → true
1059  * KJUR.lang.String.isHex("12ab") → true
1060  * KJUR.lang.String.isHex("12AB") → true
1061  * KJUR.lang.String.isHex("12ZY") → false
1062  * KJUR.lang.String.isHex("121") → false -- odd length
1063  */
1064 KJUR.lang.String.isHex = function(s) {
1065     return ishex(s);
1066 };
1067 
1068 /**
1069  * check whether a string is an hexadecimal string or not<br/>
1070  * @name ishex
1071  * @function
1072  * @static
1073  * @param {String} s input string
1074  * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false
1075  * @since base64x 1.1.7 jsrsasign 5.0.13
1076  * @example
1077  * ishex("1234") → true
1078  * ishex("12ab") → true
1079  * ishex("12AB") → true
1080  * ishex("12ZY") → false
1081  * ishex("121") → false -- odd length
1082  */
1083 function ishex(s) {
1084     if (s.length % 2 == 0 &&
1085 	(s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) {
1086 	return true;
1087     } else {
1088 	return false;
1089     }
1090 };
1091 
1092 /**
1093  * check whether a string is a base64 encoded string or not<br/>
1094  * Input string can conclude new lines or space characters.
1095  * @name isBase64
1096  * @memberOf KJUR.lang.String
1097  * @function
1098  * @static
1099  * @param {String} s input string
1100  * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false
1101  * @since base64x 1.1.7 jsrsasign 5.0.13
1102  * @example
1103  * KJUR.lang.String.isBase64("YWE=") → true
1104  * KJUR.lang.String.isBase64("YW_=") → false
1105  * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4
1106  */
1107 KJUR.lang.String.isBase64 = function(s) {
1108     s = s.replace(/\s+/g, "");
1109     if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) {
1110 	return true;
1111     } else {
1112 	return false;
1113     }
1114 };
1115 
1116 /**
1117  * check whether a string is a base64url encoded string or not<br/>
1118  * Input string can conclude new lines or space characters.
1119  * @name isBase64URL
1120  * @memberOf KJUR.lang.String
1121  * @function
1122  * @static
1123  * @param {String} s input string
1124  * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false
1125  * @since base64x 1.1.7 jsrsasign 5.0.13
1126  * @example
1127  * KJUR.lang.String.isBase64URL("YWE") → true
1128  * KJUR.lang.String.isBase64URL("YW-") → true
1129  * KJUR.lang.String.isBase64URL("YW+") → false
1130  */
1131 KJUR.lang.String.isBase64URL = function(s) {
1132     if (s.match(/[+/=]/)) return false;
1133     s = b64utob64(s);
1134     return KJUR.lang.String.isBase64(s);
1135 };
1136 
1137 /**
1138  * check whether a string is a string of integer array or not<br/>
1139  * Input string can conclude new lines or space characters.
1140  * @name isIntegerArray
1141  * @memberOf KJUR.lang.String
1142  * @function
1143  * @static
1144  * @param {String} s input string
1145  * @return {Boolean} true if a string "s" is a string of integer array otherwise false
1146  * @since base64x 1.1.7 jsrsasign 5.0.13
1147  * @example
1148  * KJUR.lang.String.isIntegerArray("[1,2,3]") → true
1149  * KJUR.lang.String.isIntegerArray("  [1, 2, 3  ] ") → true
1150  * KJUR.lang.String.isIntegerArray("[a,2]") → false
1151  */
1152 KJUR.lang.String.isIntegerArray = function(s) {
1153     s = s.replace(/\s+/g, "");
1154     if (s.match(/^\[[0-9,]+\]$/)) {
1155 	return true;
1156     } else {
1157 	return false;
1158     }
1159 };
1160 
1161 /**
1162  * check whether a string consists of PrintableString characters<br/>
1163  * @name isPrintable
1164  * @memberOf KJUR.lang.String
1165  * @function
1166  * @static
1167  * @param {String} s input string
1168  * @return {Boolean} true if a string "s" consists of PrintableString characters
1169  * @since jsrsasign 9.0.0 base64x 1.1.16
1170  * A PrintableString consists of following characters
1171  * <pre>
1172  * 0-9A-Za-z '()+,-./:=?
1173  * </pre>
1174  * This method returns false when other characters than above.
1175  * Otherwise it returns true.
1176  * @example
1177  * KJUR.lang.String.isPrintable("abc") → true
1178  * KJUR.lang.String.isPrintable("abc@") → false
1179  * KJUR.lang.String.isPrintable("あいう") → false
1180  */
1181 KJUR.lang.String.isPrintable = function(s) {
1182     if (s.match(/^[0-9A-Za-z '()+,-./:=?]*$/) !== null) return true;
1183     return false;
1184 };
1185 
1186 /**
1187  * check whether a string consists of IAString characters<br/>
1188  * @name isIA5
1189  * @memberOf KJUR.lang.String
1190  * @function
1191  * @static
1192  * @param {String} s input string
1193  * @return {Boolean} true if a string "s" consists of IA5String characters
1194  * @since jsrsasign 9.0.0 base64x 1.1.16
1195  * A IA5String consists of following characters
1196  * <pre>
1197  * %x00-21/%x23-7F (i.e. ASCII characters excludes double quote(%x22)
1198  * </pre>
1199  * This method returns false when other characters than above.
1200  * Otherwise it returns true.
1201  * @example
1202  * KJUR.lang.String.isIA5("abc") → true
1203  * KJUR.lang.String.isIA5('"abc"') → false
1204  * KJUR.lang.String.isIA5("あいう") → false
1205  */
1206 KJUR.lang.String.isIA5 = function(s) {
1207     if (s.match(/^[\x20-\x21\x23-\x7f]*$/) !== null) return true;
1208     return false;
1209 };
1210 
1211 /**
1212  * check whether a string is RFC 822 mail address<br/>
1213  * @name isMail
1214  * @memberOf KJUR.lang.String
1215  * @function
1216  * @static
1217  * @param {String} s input string
1218  * @return {Boolean} true if a string "s" RFC 822 mail address
1219  * @since jsrsasign 9.0.0 base64x 1.1.16
1220  * This static method will check string s is RFC 822 compliant mail address.
1221  * @example
1222  * KJUR.lang.String.isMail("abc") → false
1223  * KJUR.lang.String.isMail("abc@example") → false
1224  * KJUR.lang.String.isMail("abc@example.com") → true
1225  */
1226 KJUR.lang.String.isMail = function(s) {
1227     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;
1228     return false;
1229 };
1230 
1231 // ==== others ================================
1232 
1233 /**
1234  * canonicalize hexadecimal string of positive integer<br/>
1235  * @name hextoposhex
1236  * @function
1237  * @param {String} s hexadecimal string 
1238  * @return {String} canonicalized hexadecimal string of positive integer
1239  * @since base64x 1.1.10 jsrsasign 7.1.4
1240  * @description
1241  * This method canonicalize a hexadecimal string of positive integer
1242  * for two's complement representation.
1243  * Canonicalized hexadecimal string of positive integer will be:
1244  * <ul>
1245  * <li>Its length is always even.</li>
1246  * <li>If odd length it will be padded with leading zero.<li>
1247  * <li>If it is even length and its first character is "8" or greater,
1248  * it will be padded with "00" to make it positive integer.</li>
1249  * </ul>
1250  * @example
1251  * hextoposhex("abcd") → "00abcd"
1252  * hextoposhex("1234") → "1234"
1253  * hextoposhex("12345") → "012345"
1254  */
1255 function hextoposhex(s) {
1256     if (s.length % 2 == 1) return "0" + s;
1257     if (s.substr(0, 1) > "7") return "00" + s;
1258     return s;
1259 }
1260 
1261 /**
1262  * convert string of integer array to hexadecimal string.<br/>
1263  * @name intarystrtohex
1264  * @function
1265  * @param {String} s string of integer array
1266  * @return {String} hexadecimal string
1267  * @since base64x 1.1.6 jsrsasign 5.0.2
1268  * @throws "malformed integer array string: *" for wrong input
1269  * @description
1270  * This function converts a string of JavaScript integer array to
1271  * a hexadecimal string. Each integer value shall be in a range 
1272  * from 0 to 255 otherwise it raise exception. Input string can
1273  * have extra space or newline string so that they will be ignored.
1274  * 
1275  * @example
1276  * intarystrtohex(" [123, 34, 101, 34, 58] ")
1277  * → 7b2265223a (i.e. '{"e":' as string)
1278  */
1279 function intarystrtohex(s) {
1280   s = s.replace(/^\s*\[\s*/, '');
1281   s = s.replace(/\s*\]\s*$/, '');
1282   s = s.replace(/\s*/g, '');
1283   try {
1284     var hex = s.split(/,/).map(function(element, index, array) {
1285       var i = parseInt(element);
1286       if (i < 0 || 255 < i) throw "integer not in range 0-255";
1287       var hI = ("00" + i.toString(16)).slice(-2);
1288       return hI;
1289     }).join('');
1290     return hex;
1291   } catch(ex) {
1292     throw "malformed integer array string: " + ex;
1293   }
1294 }
1295 
1296 /**
1297  * find index of string where two string differs
1298  * @name strdiffidx
1299  * @function
1300  * @param {String} s1 string to compare
1301  * @param {String} s2 string to compare
1302  * @return {Number} string index of where character differs. Return -1 if same.
1303  * @since jsrsasign 4.9.0 base64x 1.1.5
1304  * @example
1305  * strdiffidx("abcdefg", "abcd4fg") -> 4
1306  * strdiffidx("abcdefg", "abcdefg") -> -1
1307  * strdiffidx("abcdefg", "abcdef") -> 6
1308  * strdiffidx("abcdefgh", "abcdef") -> 6
1309  */
1310 var strdiffidx = function(s1, s2) {
1311     var n = s1.length;
1312     if (s1.length > s2.length) n = s2.length;
1313     for (var i = 0; i < n; i++) {
1314 	if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i;
1315     }
1316     if (s1.length != s2.length) return n;
1317     return -1; // same
1318 };
1319 
1320 // ==== hex / oid =================================
1321 
1322 /**
1323  * get hexadecimal value of object identifier from dot noted oid value
1324  * @name oidtohex
1325  * @function
1326  * @param {String} oidString dot noted string of object identifier
1327  * @return {String} hexadecimal value of object identifier
1328  * @since jsrsasign 10.1.0 base64x 1.1.18
1329  * @see hextooid
1330  * @see ASN1HEX.hextooidstr
1331  * @see KJUR.asn1.ASN1Util.oidIntToHex
1332  * @description
1333  * This static method converts from object identifier value string.
1334  * to hexadecimal string representation of it.
1335  * {@link hextooid} is a reverse function of this.
1336  * @example
1337  * oidtohex("2.5.4.6") → "550406"
1338  */
1339 function oidtohex(oidString) {
1340     var itox = function(i) {
1341         var h = i.toString(16);
1342         if (h.length == 1) h = '0' + h;
1343         return h;
1344     };
1345 
1346     var roidtox = function(roid) {
1347         var h = '';
1348         var bi = parseInt(roid, 10);
1349         var b = bi.toString(2);
1350 
1351         var padLen = 7 - b.length % 7;
1352         if (padLen == 7) padLen = 0;
1353         var bPad = '';
1354         for (var i = 0; i < padLen; i++) bPad += '0';
1355         b = bPad + b;
1356         for (var i = 0; i < b.length - 1; i += 7) {
1357             var b8 = b.substr(i, 7);
1358             if (i != b.length - 7) b8 = '1' + b8;
1359             h += itox(parseInt(b8, 2));
1360         }
1361         return h;
1362     };
1363     
1364     try {
1365 	if (! oidString.match(/^[0-9.]+$/)) return null;
1366     
1367 	var h = '';
1368 	var a = oidString.split('.');
1369 	var i0 = parseInt(a[0], 10) * 40 + parseInt(a[1], 10);
1370 	h += itox(i0);
1371 	a.splice(0, 2);
1372 	for (var i = 0; i < a.length; i++) {
1373             h += roidtox(a[i]);
1374 	}
1375 	return h;
1376     } catch(ex) {
1377 	return null;
1378     }
1379 };
1380 
1381 /**
1382  * get oid string from hexadecimal value of object identifier<br/>
1383  * @name hextooid
1384  * @function
1385  * @param {String} h hexadecimal value of object identifier
1386  * @return {String} dot noted string of object identifier (ex. "1.2.3.4")
1387  * @since jsrsasign 10.1.0 base64x 1.1.18
1388  * @see oidtohex
1389  * @see ASN1HEX.hextooidstr
1390  * @see KJUR.asn1.ASN1Util.oidIntToHex
1391  * @description
1392  * This static method converts from hexadecimal object identifier value 
1393  * to dot noted OID value (ex. "1.2.3.4").
1394  * {@link oidtohex} is a reverse function of this.
1395  * @example
1396  * hextooid("550406") → "2.5.4.6"
1397  */
1398 function hextooid(h) {
1399     if (! ishex(h)) return null;
1400     try {
1401 	var a = [];
1402 
1403 	// a[0], a[1]
1404 	var hex0 = h.substr(0, 2);
1405 	var i0 = parseInt(hex0, 16);
1406 	a[0] = new String(Math.floor(i0 / 40));
1407 	a[1] = new String(i0 % 40);
1408 
1409 	// a[2]..a[n]
1410 	var hex1 = h.substr(2);
1411 	var b = [];
1412 	for (var i = 0; i < hex1.length / 2; i++) {
1413 	    b.push(parseInt(hex1.substr(i * 2, 2), 16));
1414 	}
1415 	var c = [];
1416 	var cbin = "";
1417 	for (var i = 0; i < b.length; i++) {
1418             if (b[i] & 0x80) {
1419 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1420             } else {
1421 		cbin = cbin + strpad((b[i] & 0x7f).toString(2), 7);
1422 		c.push(new String(parseInt(cbin, 2)));
1423 		cbin = "";
1424             }
1425 	}
1426 
1427 	var s = a.join(".");
1428 	if (c.length > 0) s = s + "." + c.join(".");
1429 	return s;
1430     } catch(ex) {
1431 	return null;
1432     }
1433 };
1434 
1435 /**
1436  * string padding<br/>
1437  * @name strpad
1438  * @function
1439  * @param {String} s input string
1440  * @param {Number} len output string length
1441  * @param {String} padchar padding character (default is "0")
1442  * @return {String} padded string
1443  * @since jsrsasign 10.1.0 base64x 1.1.18
1444  * @example
1445  * strpad("1234", 10, "0") → "0000001234"
1446  * strpad("1234", 10, " ") → "      1234"
1447  * strpad("1234", 10)      → "0000001234"
1448  */
1449 var strpad = function(s, len, padchar) {
1450     if (padchar == undefined) padchar = "0";
1451     if (s.length >= len) return s;
1452     return new Array(len - s.length + 1).join(padchar) + s;
1453 };
1454 
1455 // ==== bitstr hex / int =================================
1456 
1457 /**
1458  * convert from hexadecimal string of ASN.1 BitString value with unused bit to integer value<br/>
1459  * @name bitstrtoint
1460  * @function
1461  * @param {String} h hexadecimal string of ASN.1 BitString value with unused bit
1462  * @return {Number} positive integer value of the BitString
1463  * @since jsrsasign 10.1.3 base64x 1.1.19
1464  * @see inttobitstr
1465  * @see KJUR.asn1.DERBitString
1466  * @see ASN1HEX.getInt
1467  * 
1468  * @description
1469  * This function converts from hexadecimal string of ASN.1 BitString
1470  * value with unused bit to its integer value.
1471  * 
1472  * @example
1473  * // "03c8" → 0xc8 unusedbit=03 → 11001000b unusedbit=03 → 11001b → 25
1474  * bitstrtoint("03c8") → 25
1475  * // "02fff8" → 0xfff8 unusedbit=02 → 1111111111111000b unusedbit=02
1476  * //   11111111111110b → 16382
1477  * bitstrtoint("02fff8") → 16382
1478  */
1479 function bitstrtoint(h) {
1480     try {
1481 	var hUnusedbit = h.substr(0, 2);
1482 	if (hUnusedbit == "00")
1483 	    return parseInt(h.substr(2), 16);
1484 	var iUnusedbit = parseInt(hUnusedbit, 16);
1485 	var hValue = h.substr(2);
1486 	var bValue = parseInt(hValue, 16).toString(2);
1487 	if (bValue == "0") bValue = "00000000";
1488 	bValue = bValue.slice(0, 0 - iUnusedbit);
1489 	return parseInt(bValue, 2);
1490     } catch(ex) {
1491 	return -1;
1492     }
1493 };
1494 
1495 
1496 /**
1497  * convert from integer value to hexadecimal string of ASN.1 BitString value with unused bit<br/>
1498  * @name inttobitstr
1499  * @function
1500  * @param {Number} n integer value of ASN.1 BitString
1501  * @return {String} hexadecimal string of ASN.1 BitString value with unused bit
1502  * @since jsrsasign 10.1.3 base64x 1.1.19
1503  * @see bitstrtoint
1504  * @see KJUR.asn1.DERBitString
1505  * @see ASN1HEX.getInt
1506  * 
1507  * @description
1508  * This function converts from an integer value to 
1509  * hexadecimal string of ASN.1 BitString value
1510  * with unused bit.
1511  * 
1512  * @example
1513  * // 25 → 11001b → 11001000b unusedbit=03 → 0xc8 unusedbit=03 → "03c8"
1514  * inttobitstr(25) → "03c8"
1515  */
1516 function inttobitstr(n) {
1517     var bValue = Number(n).toString(2);
1518     var iUnusedbit = 8 - bValue.length % 8;
1519     if (iUnusedbit == 8) iUnusedbit = 0;
1520     bValue = bValue + strpad("", iUnusedbit, "0");
1521     var hValue = parseInt(bValue, 2).toString(16);
1522     if (hValue.length % 2 == 1) hValue = "0" + hValue;
1523     var hUnusedbit = "0" + iUnusedbit;
1524     return hUnusedbit + hValue;
1525 };
1526 
1527 /**
1528  * set class inheritance<br/>
1529  * @name extendClass
1530  * @function
1531  * @param {Function} subClass sub class to set inheritance
1532  * @param {Function} superClass super class to inherit
1533  * @since jsrsasign 10.3.0 base64x 1.1.21
1534  *
1535  * @description
1536  * This function extends a class and set an inheritance
1537  * for member variables and methods.
1538  *
1539  * @example
1540  * var Animal = function() {
1541  *   this.hello = function(){console.log("Hello")};
1542  *   this.name="Ani";
1543  * };
1544  * var Dog = function() {
1545  *   Dog.superclass.constructor.call(this);
1546  *   this.vow = function(){console.log("Vow wow")};
1547  *   this.tail=true;
1548  * };
1549  * extendClass(Dog, Animal);
1550  */
1551 function extendClass(subClass, superClass) {
1552     var F = function() {};
1553     F.prototype = superClass.prototype;
1554     subClass.prototype = new F();
1555     subClass.prototype.constructor = subClass;
1556     subClass.superclass = superClass.prototype;
1557      
1558     if (superClass.prototype.constructor == Object.prototype.constructor) {
1559         superClass.prototype.constructor = superClass;
1560     }
1561 };
1562 
1563