1 /*! base64x-1.1.8 (c) 2012-2016 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 * version: 1.1.8 (2016-Oct-16) 7 * 8 * Copyright (c) 2012-2016 Kenji Urushima (kenji.urushima@gmail.com) 9 * 10 * This software is licensed under the terms of the MIT License. 11 * http://kjur.github.com/jsjws/license/ 12 * 13 * The above copyright and license notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * DEPENDS ON: 17 * - base64.js - Tom Wu's Base64 library 18 */ 19 20 /** 21 * @fileOverview 22 * @name base64x-1.1.js 23 * @author Kenji Urushima kenji.urushima@gmail.com 24 * @version asn1 1.1.8 (2016-Oct-16) 25 * @since jsrsasign 2.1 26 * @license <a href="http://kjur.github.io/jsrsasign/license/">MIT License</a> 27 */ 28 29 var KJUR; 30 if (typeof KJUR == "undefined" || !KJUR) KJUR = {}; 31 if (typeof KJUR.lang == "undefined" || !KJUR.lang) KJUR.lang = {}; 32 33 /** 34 * String and its utility class <br/> 35 * This class provides some static utility methods for string. 36 * @class String and its utility class 37 * @author Kenji Urushima 38 * @version 1.0 (2016-Aug-05) 39 * @since base64x 1.1.7 jsrsasign 5.0.13 40 * @description 41 * <br/> 42 * This class provides static methods for string utility. 43 * <dl> 44 * <dt><b>STRING TYPE CHECKERS</b> 45 * <dd> 46 * <ul> 47 * <li>{@link KJUR.lang.String.isInteger} - check whether argument is an integer</li> 48 * <li>{@link KJUR.lang.String.isHex} - check whether argument is a hexadecimal string</li> 49 * <li>{@link KJUR.lang.String.isBase64} - check whether argument is a Base64 encoded string</li> 50 * <li>{@link KJUR.lang.String.isBase64URL} - check whether argument is a Base64URL encoded string</li> 51 * <li>{@link KJUR.lang.String.isIntegerArray} - check whether argument is an array of integers</li> 52 * </ul> 53 * </dl> 54 */ 55 KJUR.lang.String = function() {}; 56 57 /** 58 * Base64URL and supplementary functions for Tom Wu's base64.js library.<br/> 59 * This class is just provide information about global functions 60 * defined in 'base64x.js'. The 'base64x.js' script file provides 61 * global functions for converting following data each other. 62 * <ul> 63 * <li>(ASCII) String</li> 64 * <li>UTF8 String including CJK, Latin and other characters</li> 65 * <li>byte array</li> 66 * <li>hexadecimal encoded String</li> 67 * <li>Full URIComponent encoded String (such like "%69%94")</li> 68 * <li>Base64 encoded String</li> 69 * <li>Base64URL encoded String</li> 70 * </ul> 71 * All functions in 'base64x.js' are defined in {@link global__} and not 72 * in this class. 73 * 74 * @class Base64URL and supplementary functions for Tom Wu's base64.js library 75 * @author Kenji Urushima 76 * @version 1.1 (07 May 2012) 77 * @requires base64.js 78 * @see <a href="http://kjur.github.com/jsjws/">'jwjws'(JWS JavaScript Library) home page http://kjur.github.com/jsjws/</a> 79 * @see <a href="http://kjur.github.com/jsrsasigns/">'jwrsasign'(RSA Sign JavaScript Library) home page http://kjur.github.com/jsrsasign/</a> 80 */ 81 function Base64x() { 82 } 83 84 // ==== string / byte array ================================ 85 /** 86 * convert a string to an array of character codes 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 * @param {Array of Numbers} a array of character codes 101 * @return {String} s 102 */ 103 function BAtos(a) { 104 var s = ""; 105 for (var i = 0; i < a.length; i++) { 106 s = s + String.fromCharCode(a[i]); 107 } 108 return s; 109 } 110 111 // ==== byte array / hex ================================ 112 /** 113 * convert an array of bytes(Number) to hexadecimal string.<br/> 114 * @param {Array of Numbers} a array of bytes 115 * @return {String} hexadecimal string 116 */ 117 function BAtohex(a) { 118 var s = ""; 119 for (var i = 0; i < a.length; i++) { 120 var hex1 = a[i].toString(16); 121 if (hex1.length == 1) hex1 = "0" + hex1; 122 s = s + hex1; 123 } 124 return s; 125 } 126 127 // ==== string / hex ================================ 128 /** 129 * convert a ASCII string to a hexadecimal string of ASCII codes.<br/> 130 * NOTE: This can't be used for non ASCII characters. 131 * @param {s} s ASCII string 132 * @return {String} hexadecimal string 133 */ 134 function stohex(s) { 135 return BAtohex(stoBA(s)); 136 } 137 138 // ==== string / base64 ================================ 139 /** 140 * convert a ASCII string to a Base64 encoded string.<br/> 141 * NOTE: This can't be used for non ASCII characters. 142 * @param {s} s ASCII string 143 * @return {String} Base64 encoded string 144 */ 145 function stob64(s) { 146 return hex2b64(stohex(s)); 147 } 148 149 // ==== string / base64url ================================ 150 /** 151 * convert a ASCII string to a Base64URL encoded string.<br/> 152 * NOTE: This can't be used for non ASCII characters. 153 * @param {s} s ASCII string 154 * @return {String} Base64URL encoded string 155 */ 156 function stob64u(s) { 157 return b64tob64u(hex2b64(stohex(s))); 158 } 159 160 /** 161 * convert a Base64URL encoded string to a ASCII string.<br/> 162 * NOTE: This can't be used for Base64URL encoded non ASCII characters. 163 * @param {s} s Base64URL encoded string 164 * @return {String} ASCII string 165 */ 166 function b64utos(s) { 167 return BAtos(b64toBA(b64utob64(s))); 168 } 169 170 // ==== base64 / base64url ================================ 171 /** 172 * convert a Base64 encoded string to a Base64URL encoded string.<br/> 173 * @param {String} s Base64 encoded string 174 * @return {String} Base64URL encoded string 175 * @example 176 * b64tob64u("ab+c3f/==") → "ab-c3f_" 177 */ 178 function b64tob64u(s) { 179 s = s.replace(/\=/g, ""); 180 s = s.replace(/\+/g, "-"); 181 s = s.replace(/\//g, "_"); 182 return s; 183 } 184 185 /** 186 * convert a Base64URL encoded string to a Base64 encoded string.<br/> 187 * @param {String} s Base64URL encoded string 188 * @return {String} Base64 encoded string 189 * @example 190 * b64utob64("ab-c3f_") → "ab+c3f/==" 191 */ 192 function b64utob64(s) { 193 if (s.length % 4 == 2) s = s + "=="; 194 else if (s.length % 4 == 3) s = s + "="; 195 s = s.replace(/-/g, "+"); 196 s = s.replace(/_/g, "/"); 197 return s; 198 } 199 200 // ==== hex / base64url ================================ 201 /** 202 * convert a hexadecimal string to a Base64URL encoded string.<br/> 203 * @param {String} s hexadecimal string 204 * @return {String} Base64URL encoded string 205 * @description 206 * convert a hexadecimal string to a Base64URL encoded string. 207 * NOTE: If leading "0" is omitted and odd number length for 208 * hexadecimal leading "0" is automatically added. 209 */ 210 function hextob64u(s) { 211 if (s.length % 2 == 1) s = "0" + s; 212 return b64tob64u(hex2b64(s)); 213 } 214 215 /** 216 * convert a Base64URL encoded string to a hexadecimal string.<br/> 217 * @param {String} s Base64URL encoded string 218 * @return {String} hexadecimal string 219 */ 220 function b64utohex(s) { 221 return b64tohex(b64utob64(s)); 222 } 223 224 // ==== utf8 / base64url ================================ 225 226 /** 227 * convert a UTF-8 encoded string including CJK or Latin to a Base64URL encoded string.<br/> 228 * @param {String} s UTF-8 encoded string 229 * @return {String} Base64URL encoded string 230 * @since 1.1 231 */ 232 233 /** 234 * convert a Base64URL encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 235 * @param {String} s Base64URL encoded string 236 * @return {String} UTF-8 encoded string 237 * @since 1.1 238 */ 239 240 var utf8tob64u, b64utoutf8; 241 242 if (typeof Buffer === 'function') { 243 utf8tob64u = function (s) { 244 return b64tob64u(new Buffer(s, 'utf8').toString('base64')); 245 }; 246 247 b64utoutf8 = function (s) { 248 return new Buffer(b64utob64(s), 'base64').toString('utf8'); 249 }; 250 } else { 251 utf8tob64u = function (s) { 252 return hextob64u(uricmptohex(encodeURIComponentAll(s))); 253 }; 254 255 b64utoutf8 = function (s) { 256 return decodeURIComponent(hextouricmp(b64utohex(s))); 257 }; 258 } 259 260 // ==== utf8 / base64url ================================ 261 /** 262 * convert a UTF-8 encoded string including CJK or Latin to a Base64 encoded string.<br/> 263 * @param {String} s UTF-8 encoded string 264 * @return {String} Base64 encoded string 265 * @since 1.1.1 266 */ 267 function utf8tob64(s) { 268 return hex2b64(uricmptohex(encodeURIComponentAll(s))); 269 } 270 271 /** 272 * convert a Base64 encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 273 * @param {String} s Base64 encoded string 274 * @return {String} UTF-8 encoded string 275 * @since 1.1.1 276 */ 277 function b64toutf8(s) { 278 return decodeURIComponent(hextouricmp(b64tohex(s))); 279 } 280 281 // ==== utf8 / hex ================================ 282 /** 283 * convert a UTF-8 encoded string including CJK or Latin to a hexadecimal encoded string.<br/> 284 * @param {String} s UTF-8 encoded string 285 * @return {String} hexadecimal encoded string 286 * @since 1.1.1 287 */ 288 function utf8tohex(s) { 289 return uricmptohex(encodeURIComponentAll(s)); 290 } 291 292 /** 293 * convert a hexadecimal encoded string to a UTF-8 encoded string including CJK or Latin.<br/> 294 * Note that when input is improper hexadecimal string as UTF-8 string, this function returns 295 * 'null'. 296 * @param {String} s hexadecimal encoded string 297 * @return {String} UTF-8 encoded string or null 298 * @since 1.1.1 299 */ 300 function hextoutf8(s) { 301 return decodeURIComponent(hextouricmp(s)); 302 } 303 304 /** 305 * convert a hexadecimal encoded string to raw string including non printable characters.<br/> 306 * @param {String} s hexadecimal encoded string 307 * @return {String} raw string 308 * @since 1.1.2 309 * @example 310 * hextorstr("610061") → "a\x00a" 311 */ 312 function hextorstr(sHex) { 313 var s = ""; 314 for (var i = 0; i < sHex.length - 1; i += 2) { 315 s += String.fromCharCode(parseInt(sHex.substr(i, 2), 16)); 316 } 317 return s; 318 } 319 320 /** 321 * convert a raw string including non printable characters to hexadecimal encoded string.<br/> 322 * @param {String} s raw string 323 * @return {String} hexadecimal encoded string 324 * @since 1.1.2 325 * @example 326 * rstrtohex("a\x00a") → "610061" 327 */ 328 function rstrtohex(s) { 329 var result = ""; 330 for (var i = 0; i < s.length; i++) { 331 result += ("0" + s.charCodeAt(i).toString(16)).slice(-2); 332 } 333 return result; 334 } 335 336 // ==== hex / b64nl ======================================= 337 338 /** 339 * convert a hexadecimal string to Base64 encoded string<br/> 340 * @param {String} s hexadecimal string 341 * @return {String} resulted Base64 encoded string 342 * @since base64x 1.1.3 343 * @description 344 * This function converts from a hexadecimal string to Base64 encoded 345 * string without new lines. 346 * @example 347 * hextob64("616161") → "YWFh" 348 */ 349 function hextob64(s) { 350 return hex2b64(s); 351 } 352 353 /** 354 * convert a hexadecimal string to Base64 encoded string with new lines<br/> 355 * @param {String} s hexadecimal string 356 * @return {String} resulted Base64 encoded string with new lines 357 * @since base64x 1.1.3 358 * @description 359 * This function converts from a hexadecimal string to Base64 encoded 360 * string with new lines for each 64 characters. This is useful for 361 * PEM encoded file. 362 * @example 363 * hextob64nl("123456789012345678901234567890123456789012345678901234567890") 364 * → 365 * MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4 // new line 366 * OTAxMjM0NTY3ODkwCg== 367 */ 368 function hextob64nl(s) { 369 var b64 = hextob64(s); 370 var b64nl = b64.replace(/(.{64})/g, "$1\r\n"); 371 b64nl = b64nl.replace(/\r\n$/, ''); 372 return b64nl; 373 } 374 375 /** 376 * convert a Base64 encoded string with new lines to a hexadecimal string<br/> 377 * @param {String} s Base64 encoded string with new lines 378 * @return {String} hexadecimal string 379 * @since base64x 1.1.3 380 * @description 381 * This function converts from a Base64 encoded 382 * string with new lines to a hexadecimal string. 383 * This is useful to handle PEM encoded file. 384 * This function removes any non-Base64 characters (i.e. not 0-9,A-Z,a-z,\,+,=) 385 * including new line. 386 * @example 387 * hextob64nl( 388 * "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0NTY3ODkwMTIzNDU2Nzg5MDEyMzQ1Njc4\r\n" + 389 * "OTAxMjM0NTY3ODkwCg==\r\n") 390 * → 391 * "123456789012345678901234567890123456789012345678901234567890" 392 */ 393 function b64nltohex(s) { 394 var b64 = s.replace(/[^0-9A-Za-z\/+=]*/g, ''); 395 var hex = b64tohex(b64); 396 return hex; 397 } 398 399 // ==== hex / ArrayBuffer ================================= 400 401 /** 402 * convert a ArrayBuffer to a hexadecimal string<br/> 403 * @param {String} hex hexadecimal string 404 * @return {ArrayBuffer} ArrayBuffer 405 * @since jsrsasign 6.1.4 base64x 1.1.8 406 * @description 407 * This function converts from a ArrayBuffer to a hexadecimal string. 408 * @example 409 * var buffer = new ArrayBuffer(3); 410 * var view = new DataView(buffer); 411 * view.setUint8(0, 0xfa); 412 * view.setUint8(1, 0xfb); 413 * view.setUint8(2, 0x01); 414 * ArrayBuffertohex(buffer) → "fafb01" 415 */ 416 function hextoArrayBuffer(hex) { 417 if (hex.length % 2 != 0) throw "input is not even length"; 418 if (hex.match(/^[0-9A-Fa-f]+$/) == null) throw "input is not hexadecimal"; 419 420 var buffer = new ArrayBuffer(hex.length / 2); 421 var view = new DataView(buffer); 422 423 for (var i = 0; i < hex.length / 2; i++) { 424 view.setUint8(i, parseInt(hex.substr(i * 2, 2), 16)); 425 } 426 427 return buffer; 428 } 429 430 // ==== ArrayBuffer / hex ================================= 431 432 /** 433 * convert a ArrayBuffer to a hexadecimal string<br/> 434 * @param {ArrayBuffer} buffer ArrayBuffer 435 * @return {String} hexadecimal string 436 * @since jsrsasign 6.1.4 base64x 1.1.8 437 * @description 438 * This function converts from a ArrayBuffer to a hexadecimal string. 439 * @example 440 * hextoArrayBuffer("fffa01") → ArrayBuffer of [255, 250, 1] 441 */ 442 function ArrayBuffertohex(buffer) { 443 var hex = ""; 444 var view = new DataView(buffer); 445 446 for (var i = 0; i < buffer.byteLength; i++) { 447 hex += ("00" + view.getUint8(i).toString(16)).slice(-2); 448 } 449 450 return hex; 451 } 452 453 // ==== URIComponent / hex ================================ 454 /** 455 * convert a URLComponent string such like "%67%68" to a hexadecimal string.<br/> 456 * @param {String} s URIComponent string such like "%67%68" 457 * @return {String} hexadecimal string 458 * @since 1.1 459 */ 460 function uricmptohex(s) { 461 return s.replace(/%/g, ""); 462 } 463 464 /** 465 * convert a hexadecimal string to a URLComponent string such like "%67%68".<br/> 466 * @param {String} s hexadecimal string 467 * @return {String} URIComponent string such like "%67%68" 468 * @since 1.1 469 */ 470 function hextouricmp(s) { 471 return s.replace(/(..)/g, "%$1"); 472 } 473 474 // ==== URIComponent ================================ 475 /** 476 * convert UTFa hexadecimal string to a URLComponent string such like "%67%68".<br/> 477 * Note that these "<code>0-9A-Za-z!'()*-._~</code>" characters will not 478 * converted to "%xx" format by builtin 'encodeURIComponent()' function. 479 * However this 'encodeURIComponentAll()' function will convert 480 * all of characters into "%xx" format. 481 * @param {String} s hexadecimal string 482 * @return {String} URIComponent string such like "%67%68" 483 * @since 1.1 484 */ 485 function encodeURIComponentAll(u8) { 486 var s = encodeURIComponent(u8); 487 var s2 = ""; 488 for (var i = 0; i < s.length; i++) { 489 if (s[i] == "%") { 490 s2 = s2 + s.substr(i, 3); 491 i = i + 2; 492 } else { 493 s2 = s2 + "%" + stohex(s[i]); 494 } 495 } 496 return s2; 497 } 498 499 // ==== new lines ================================ 500 /** 501 * convert all DOS new line("\r\n") to UNIX new line("\n") in 502 * a String "s". 503 * @param {String} s string 504 * @return {String} converted string 505 */ 506 function newline_toUnix(s) { 507 s = s.replace(/\r\n/mg, "\n"); 508 return s; 509 } 510 511 /** 512 * convert all UNIX new line("\r\n") to DOS new line("\n") in 513 * a String "s". 514 * @param {String} s string 515 * @return {String} converted string 516 */ 517 function newline_toDos(s) { 518 s = s.replace(/\r\n/mg, "\n"); 519 s = s.replace(/\n/mg, "\r\n"); 520 return s; 521 } 522 523 // ==== string type checker =================== 524 525 /** 526 * check whether a string is an integer string or not<br/> 527 * @name isInteger 528 * @memberOf KJUR.lang.String 529 * @function 530 * @static 531 * @param {String} s input string 532 * @return {Boolean} true if a string "s" is an integer string otherwise false 533 * @since base64x 1.1.7 jsrsasign 5.0.13 534 * @example 535 * KJUR.lang.String.isInteger("12345") → true 536 * KJUR.lang.String.isInteger("123ab") → false 537 */ 538 KJUR.lang.String.isInteger = function(s) { 539 if (s.match(/^[0-9]+$/)) { 540 return true; 541 } else if (s.match(/^-[0-9]+$/)) { 542 return true; 543 } else { 544 return false; 545 } 546 }; 547 548 /** 549 * check whether a string is an hexadecimal string or not<br/> 550 * @name isHex 551 * @memberOf KJUR.lang.String 552 * @function 553 * @static 554 * @param {String} s input string 555 * @return {Boolean} true if a string "s" is an hexadecimal string otherwise false 556 * @since base64x 1.1.7 jsrsasign 5.0.13 557 * @example 558 * KJUR.lang.String.isHex("1234") → true 559 * KJUR.lang.String.isHex("12ab") → true 560 * KJUR.lang.String.isHex("12AB") → true 561 * KJUR.lang.String.isHex("12ZY") → false 562 * KJUR.lang.String.isHex("121") → false -- odd length 563 */ 564 KJUR.lang.String.isHex = function(s) { 565 if (s.length % 2 == 0 && 566 (s.match(/^[0-9a-f]+$/) || s.match(/^[0-9A-F]+$/))) { 567 return true; 568 } else { 569 return false; 570 } 571 }; 572 573 /** 574 * check whether a string is a base64 encoded string or not<br/> 575 * Input string can conclude new lines or space characters. 576 * @name isBase64 577 * @memberOf KJUR.lang.String 578 * @function 579 * @static 580 * @param {String} s input string 581 * @return {Boolean} true if a string "s" is a base64 encoded string otherwise false 582 * @since base64x 1.1.7 jsrsasign 5.0.13 583 * @example 584 * KJUR.lang.String.isBase64("YWE=") → true 585 * KJUR.lang.String.isBase64("YW_=") → false 586 * KJUR.lang.String.isBase64("YWE") → false -- length shall be multiples of 4 587 */ 588 KJUR.lang.String.isBase64 = function(s) { 589 s = s.replace(/\s+/g, ""); 590 if (s.match(/^[0-9A-Za-z+\/]+={0,3}$/) && s.length % 4 == 0) { 591 return true; 592 } else { 593 return false; 594 } 595 }; 596 597 /** 598 * check whether a string is a base64url encoded string or not<br/> 599 * Input string can conclude new lines or space characters. 600 * @name isBase64URL 601 * @memberOf KJUR.lang.String 602 * @function 603 * @static 604 * @param {String} s input string 605 * @return {Boolean} true if a string "s" is a base64url encoded string otherwise false 606 * @since base64x 1.1.7 jsrsasign 5.0.13 607 * @example 608 * KJUR.lang.String.isBase64URL("YWE") → true 609 * KJUR.lang.String.isBase64URL("YW-") → true 610 * KJUR.lang.String.isBase64URL("YW+") → false 611 */ 612 KJUR.lang.String.isBase64URL = function(s) { 613 if (s.match(/[+/=]/)) return false; 614 s = b64utob64(s); 615 return KJUR.lang.String.isBase64(s); 616 }; 617 618 /** 619 * check whether a string is a string of integer array or not<br/> 620 * Input string can conclude new lines or space characters. 621 * @name isIntegerArray 622 * @memberOf KJUR.lang.String 623 * @function 624 * @static 625 * @param {String} s input string 626 * @return {Boolean} true if a string "s" is a string of integer array otherwise false 627 * @since base64x 1.1.7 jsrsasign 5.0.13 628 * @example 629 * KJUR.lang.String.isIntegerArray("[1,2,3]") → true 630 * KJUR.lang.String.isIntegerArray(" [1, 2, 3 ] ") → true 631 * KJUR.lang.String.isIntegerArray("[a,2]") → false 632 */ 633 KJUR.lang.String.isIntegerArray = function(s) { 634 s = s.replace(/\s+/g, ""); 635 if (s.match(/^\[[0-9,]+\]$/)) { 636 return true; 637 } else { 638 return false; 639 } 640 }; 641 642 // ==== others ================================ 643 644 /** 645 * convert string of integer array to hexadecimal string.<br/> 646 * @param {String} s string of integer array 647 * @return {String} hexadecimal string 648 * @since base64x 1.1.6 jsrsasign 5.0.2 649 * @throws "malformed integer array string: *" for wrong input 650 * @description 651 * This function converts a string of JavaScript integer array to 652 * a hexadecimal string. Each integer value shall be in a range 653 * from 0 to 255 otherwise it raise exception. Input string can 654 * have extra space or newline string so that they will be ignored. 655 * 656 * @example 657 * intarystrtohex(" [123, 34, 101, 34, 58] ") 658 * → 7b2265223a (i.e. '{"e":' as string) 659 */ 660 function intarystrtohex(s) { 661 s = s.replace(/^\s*\[\s*/, ''); 662 s = s.replace(/\s*\]\s*$/, ''); 663 s = s.replace(/\s*/g, ''); 664 try { 665 var hex = s.split(/,/).map(function(element, index, array) { 666 var i = parseInt(element); 667 if (i < 0 || 255 < i) throw "integer not in range 0-255"; 668 var hI = ("00" + i.toString(16)).slice(-2); 669 return hI; 670 }).join(''); 671 return hex; 672 } catch(ex) { 673 throw "malformed integer array string: " + ex; 674 } 675 } 676 677 /** 678 * find index of string where two string differs 679 * @param {String} s1 string to compare 680 * @param {String} s2 string to compare 681 * @return {Number} string index of where character differs. Return -1 if same. 682 * @since jsrsasign 4.9.0 base64x 1.1.5 683 * @example 684 * strdiffidx("abcdefg", "abcd4fg") -> 4 685 * strdiffidx("abcdefg", "abcdefg") -> -1 686 * strdiffidx("abcdefg", "abcdef") -> 6 687 * strdiffidx("abcdefgh", "abcdef") -> 6 688 */ 689 var strdiffidx = function(s1, s2) { 690 var n = s1.length; 691 if (s1.length > s2.length) n = s2.length; 692 for (var i = 0; i < n; i++) { 693 if (s1.charCodeAt(i) != s2.charCodeAt(i)) return i; 694 } 695 if (s1.length != s2.length) return n; 696 return -1; // same 697 }; 698 699 700