// Itai Hareven itaiha@openu.ac.il // Telem, 2004 var alertOnBase64Errors = new Boolean(true); function decodeBase64(s, paddingChar, shiftBy) { /* Decode string s from base64. paddingChar is the char used to pad the base64 string at the right, customarily it is "=" , we allow for other values, since the default might not be desirable e.g. in a cookie. shiftBy is an optional numerical shift, applied after decoding to each charCode in the decoded string that is higher than 127. This is used to reach higher unicode values that were shifted down while encoding. uBeIvrit Pshuta: we shift to restore the Hebrew ... */ if (typeof(paddingChar) =="undefined") paddingChar = "="; if (typeof(shiftBy) =="undefined") shiftBy = 0; if (typeof(shiftStart) =="undefined") shiftStart = 0; if (typeof(shiftEnd) =="undefined") shiftEnd = 256; keyBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; keyBase64 += keyBase64.toLowerCase(); keyBase64 += "0123456789"; keyBase64 += "+/"; var sDecoded = ""; var codesMiniArray = new Array(4); var chunk = ""; var binaryChunk = 0; var code0 = 0, code1 = 0, code2 = 0; var sTemp = cleanAndValidate(s, paddingChar); while (sTemp.length > 0) { chunk = sTemp.substr(0, 4); // get 4 chars, or less if sTemp is shorter than 4 sTemp = sTemp.substr(4, sTemp.length); //alert("chunk=" +chunk +"\nsTemp=" +sTemp); // from the loop test + previous validation, we have at least 2 chars in chunk codesMiniArray[0] = keyBase64.indexOf(chunk.charAt(0)); // 0 ... 63 codesMiniArray[1] = keyBase64.indexOf(chunk.charAt(1)); codesMiniArray[2] = (chunk.length >2) ? keyBase64.indexOf(chunk.charAt(2)) : 0; codesMiniArray[3] = (chunk.length >3) ? keyBase64.indexOf(chunk.charAt(3)) : 0; // create a 24-bit sequence from the base64 codes of the chars in chunk // by repeatedly shifting 6 bits to the left and adding: binaryChunk = 0; for (var i=0; i<4; i++) binaryChunk = (binaryChunk << 6) | codesMiniArray[i] ; // divide the 24 bits into 3 bytes. // later ignore 2nd and 3rd bytes if chunk.length was too small code0 = binaryChunk >> 16; code1 = (binaryChunk >> 8) & 255; code2 = binaryChunk & 255; sDecoded += getCharFromCode(code0, shiftBy); if (chunk.length >2) sDecoded += getCharFromCode(code1, shiftBy); if (chunk.length >3) sDecoded += getCharFromCode(code2, shiftBy); } // alert(sDecoded); return(sDecoded); } function getCharFromCode(cCode, shiftBy) { var charCode = parseInt(cCode); if ((shiftBy) && (charCode > 127) && (charCode < 256)) charCode += parseInt(shiftBy); return(String.fromCharCode(charCode)); } function cleanAndValidate(base64StrOrig, paddingChar) { var errorMessages = new Array(); var sOpeningErrorMessage = "The following problems were encountered when decoding from base64:"; var sErrorMessage = "", sMore = ""; var base64Str = base64StrOrig; if ((base64Str.length) %4) errorMessages.push("number of chars is not a multiple of 4"); // discard everything from first paddingChar to the end if (base64Str.match(paddingChar)) base64Str = base64Str.substring(0, base64Str.indexOf(paddingChar)); // check for invalid chars in data. if (base64Str.match(/[^A-Za-z0-9\+\/]/)) { errorMessages.push("data contained one or more characters not in Base64, they were removed."); base64Str = base64Str.replace(/[^A-Za-z0-9\+\/]/g, ""); // remove the junk and try to go on... } // after paddingChars are removed, number of base64 chars mod 4 must be 0, 2 or 3: if ((base64Str.length)%4 ==1) { errorMessages.push("last char in base64 was removed to preserve consistency of data."); base64Str = base64Str.substring(0, base64Str.length-1); } if ((errorMessages.length >0) && (alertOnBase64Errors==true)) { sErrorMessage += sOpeningErrorMessage; sErrorMessage += "\n\n* " +errorMessages.join("\n\n* "); try { sMore = "\n\nNote: the base64 data was: " +base64StrOrig; alert(sErrorMessage +sMore); } catch (base64StringReallyReallyBad) { sMore = "\n\nthe base64 data could not be displayed"; alert(sErrorMessage +sMore); } } return(base64Str); }