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