I have the following string:
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
Is there a javascript string compression function that can shorten this somehow?
I also need a way to extract it back to its original string state.
The idea is to convert the available base62 string into a higher base string. This way you save space. But doing this in vanilla JS (or using Jquery) is difficult because JS doesn't handle big numbers very well. With the help of an external library bigint.js, it is possible. You can test it here. This code was not written by me, but its quite useful:
var base_symbols = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz~`!##$%^&*()-_=+[{]}\\|;:'\",<.>/?¿¡";
function baseConvert(src, from_base, to_base, src_symbol_table, dest_symbol_table) {
// From: convert.js: http://rot47.net/_js/convert.js
// Modified by MLM to work with BigInteger: https://github.com/peterolson/BigInteger.js
src_symbol_table = src_symbol_table ? src_symbol_table : base_symbols;
dest_symbol_table = dest_symbol_table ? dest_symbol_table : src_symbol_table;
if(from_base > src_symbol_table.length || to_base > dest_symbol_table.length) {
console.warn("Can't convert", src, "to base", to_base, "greater than symbol table length. src-table:", src_symbol_table.length, "dest-table:", dest_symbol_table.length);
return false;
}
var val = bigInt(0);
for(var i = 0; i < src.length; i ++) {
val = val.multiply(from_base).add(src_symbol_table.indexOf(src.charAt(i)));
}
if(val.lesser(0)) {
return 0;
}
var r = val.mod(to_base);
var res = dest_symbol_table.charAt(r);
var q = val.divide(to_base);
while(!q.equals(0)) {
r = q.mod(to_base);
q = q.divide(to_base);
res = dest_symbol_table.charAt(r) + res;
}
return res;
}
var input = 'SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3';
var a = baseConvert(input, 62, 80);
baseConvert(a, 80, 62);
The resultant output converts 94 characters into 82 characters:
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
$sIn3#WAto¿rf<zVn"+:Pkgq;&x.fciVZC7O)`0ii+sf/\X¿CM9Ad!0Z^q?t6uK=w}S8=JZhboIHd'fY\]Qf
SigV1i8njyrAGrbAfHRNdM3fmEu3kd7keGsqTTDG3Wt3tXqT153eFya2JsEigrK7Pjmh6HhEQLp5bmNXyeHsKNELW7cD3
To get better compression, just chanage the base_symbols to include a lot more characters and then convert the input into an even higher base.
hosts=".uk.com:hostname:#10.10.10.10/10:#[2001:db8:1/64]:#11.11.11.11/11:#[::2/24]"
In javascript, how do i split the above string("hosts") string like the following :
newhosts=.uk.com,hostname,#10.10.10.10/10,#[2001:db8:1/64],#11.11.11.11/11,#[::2/24]"
tried this :
var hosts, newhosts;
var ip6_hosts = [];
var ip6_re = /#\[(.*?)\]/g;
hosts=".uk.com:hostname:#10.10.10.10/10:#[2001:db8:1/64]:#11.11.11.11/11:#[::2/24]";
while ((match=ip6_re.exec(hosts)) != null)
ip6_hosts.push(match[0]);
non_ip6_hosts=hosts.replace(ip6_re, '').replace(/:+/g, ':');
newhosts=ip6_hosts.concat(non_ip6_hosts.split(':'));
actual output :
newhosts=#[2001:db8:1/64],#[::2/24],.uk.com,hostname,#10.10.10.10/10,#11.11.11.11/11
expected output :
newhosts=.uk.com,hostname,#10.10.10.10/10,#[2001:db8:1/64],#11.11.11.11/11,#[::2/24]
but not sure how to preserve the order. is there any way to achieve an expected output ?
You could try:
var openbracket=0;
for (i=0; i<hosts.length; i++)
{
if (hosts.substr(i,1) == '[') openbracket=openbracket+1;
if (hosts.substr(i,1) == ']') openbracket=openbracket-1;
if ((hosts.substr(i,1) == ':') && openbracket==0)
{
hosts = hosts.substr(0,i) + ',' + hosts.substr(i+1,hosts.length-i-1);
}
}
seems to work for me, though I'm not sure if there's a better method for changing the value of hosts. All it needs to do is insert the ',' at the location i. The above code adds everything to the left of the ':', a ',', and everything to the right of the ':'.
note: this assumes you don't want any ':' inside of brackets changed to a comma.
hope this helps.
Can't You just say:
host = host.replace(/:+/, ',');
whenever you want to change it?
I feel like this is too simple of an answer, comment if I'm not getting it.
The following should work:
hosts.replace(/([^:]{1})\:{1}([^:]{1})/g, '$1,$2')
Try this.
var hosts='.uk.com:hostname:#10.10.10.10/10:#[2001:db8:1/64]:#11.11.11.11/11:#[::2/24]';
hosts = hosts.replace(/:#/g, ':##');
hosts = hosts.split(':#');
var hostDetails = hosts[0].split(':');
var newHost = hostDetails.concat(hosts.splice(1, hosts.length));
console.log(newHost);
Can you try this...
String.prototype.replaceAt=function(index, character) {
return this.substr(0, index) + character + this.substr(index+character.length);
}
hosts=".uk.com:hostname:#10.10.10.10/10:#[2001:db8:1/64]:#11.11.11.11/11:#[::2/24]"
hosts = hosts.split(':#').join(',#');
var re = /:\w/g;
var found = hosts.match(re);
hosts.replaceAt(found.index,',');
I have this piece of javascript code
var file = Components.classes["#mozilla.org/file/local;1"]
.createInstance(Components.interfaces.nsILocalFile);
file.initWithPath( this.savefile );
if ( file.exists() == false ) {
return null;
}
var is = Components.classes["#mozilla.org/network/file-input-stream;1"]
.createInstance( Components.interfaces.nsIFileInputStream );
is.init( file,0x01, 00004, null);
var sis = Components.classes["#mozilla.org/scriptableinputstream;1"]
.createInstance( Components.interfaces.nsIScriptableInputStream );
sis.init( is );
output = sis.read( sis.available() );
sis.close();
is.close();
this.filterData = output;
return output;
Actually the file that i am reading is a binary file and has lets say 350 bytes.
Now the 19 byte is "zero", so what happens is in the above code i get only 18 bytes in output.
when i tried debugging sis.available does return 350. But sis.read only reads upto Zero byte.
I want the way to read whole of 350 bytes in output.
EDIT
See https://developer.mozilla.org/en-US/docs/Reading_textual_data
Quote:
var charset = /* Need to find out what the character encoding is. Using UTF-8 for this example: */ "UTF-8";
var is = Components.classes["#mozilla.org/intl/converter-input-stream;1"]
.createInstance(Components.interfaces.nsIConverterInputStream);
// This assumes that fis is the nsIInputStream you want to read from
is.init(fis, charset, 1024, 0xFFFD);
is.QueryInterface(Components.interfaces.nsIUnicharLineInputStream);
if (is instanceof Components.interfaces.nsIUnicharLineInputStream) {
var line = {};
var cont;
do {
cont = is.readLine(line);
// Now you can do something with line.value
} while (cont);
}
This avoids the null byte problems, is unicode safe, and works with less esoteric object types.
Original:
As per my comment above, and in light of your edit,
See https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIScriptableInputStream where read() comes with the warning: If the data contains a null byte, then this method will return a truncated string. You may want to use readBytes() instead.
Alternatively, here's another way to do it:
var ph = Components.classes["#mozilla.org/network/protocol;1?name=file"]
.createInstance(Components.interfaces.nsIFileProtocolHandler);
var file_to_read = ph.getURLSpecFromFile(file);
var req = new XMLHttpRequest();
req.onerror = function(e) {
onError(e);
}
req.onreadystatechange = function() {
if (log.readyState == 4) {
//...
}
}
req.open("GET", file_to_read, true);
I may be wrong, but have you tried sending a simple GET request? In AJAX? Or do you strictly want to use JS?
EDIT:
Refer to this - How do I load the contents of a text file into a javascript variable?
My urls will look like:
http://example.com/whatever#page?x=1&locale=hu&y=2
http://example.com/whatever#page?x=1&locale=hu
http://example.com/whatever#page?locale=hu
http://example.com/whatever#page?locale=
http://example.com/whatever#page?x=1
http://example.com/whatever#page
http://example.com/whatever
I'd like to get the locale parameter or empty string if it's not set.
I'm trying something like:
locale = location.hash.replace(/.*(?:[?&]locale=([^&]*))?.*/, "$2");
But my problem is that I couldn't find the right RegExp that works for all cases (both when there's locale= in the hash and when there isn't)
Here's a piece of code that will extract it from the hash and avoid it anywhere else in the URL:
function getLocaleFromHash(url) {
var match = url.match(/#.*[?&]locale=([^&]+)(&|$)/);
return(match ? match[1] : "");
}
And, you can see it work on all your test cases here: http://jsfiddle.net/jfriend00/p37Mx/
If you want to be able to look for any parm in the hash, you would use this:
function getParmFromHash(url, parm) {
var re = new RegExp("#.*[?&]" + parm + "=([^&]+)(&|$)");
var match = url.match(re);
return(match ? match[1] : "");
}
See it work here: http://jsfiddle.net/jfriend00/6kgUk/
A more generic function that will fetch all parameters in the URL would look like this. For normal URLs where the hash is after the query and the parameters are in the query string, it would look like this. This is a bit more code because it does more. It fetches all the parameters into an object where you can look up any parameter by it's key and it URL decodes them all too:
function getParmsFromURL(url) {
var parms = {}, pieces, parts, i;
var hash = url.lastIndexOf("#");
if (hash !== -1) {
// remove hash value
url = url.slice(0, hash);
}
var question = url.lastIndexOf("?");
if (question !== -1) {
url = url.slice(question + 1);
pieces = url.split("&");
for (i = 0; i < pieces.length; i++) {
parts = pieces[i].split("=");
if (parts.length < 2) {
parts.push("");
}
parms[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
}
return parms;
}
For a special version that handles parameters in a hash value and after a ? in the hash value like in the OP's question (which isn't the typical case), one could use this:
function getParmsFromURLHash(url) {
var parms = {}, pieces, parts, i;
var hash = url.lastIndexOf("#");
if (hash !== -1) {
// isolate just the hash value
url = url.slice(hash + 1);
}
var question = url.indexOf("?");
if (question !== -1) {
url = url.slice(question + 1);
pieces = url.split("&");
for (i = 0; i < pieces.length; i++) {
parts = pieces[i].split("=");
if (parts.length < 2) {
parts.push("");
}
parms[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]);
}
}
return parms;
}
Working demo: http://jsfiddle.net/jfriend00/v8cd5/
And, then if you wanted the local option, you'd just do this:
var parms = getParmsFromURL(url);
var locale = parms["locale"];
locale = location.hash.match( /[?&]locale=([^&]*)?/ );
locale = ( locale == null ? "" : locale[1] || "" );
Will do the trick. I don't think the .* are needed, because you do not specify a start or an end of the string.
I tested this regular expression on all your examples and they all worked correctly :)
Edit: sorry, it was invalid in some cases. It is now correct in all cases.
If you really want to do it in one regex:
locale = location.hash.match(/([?&]locale=|^((?![?&]locale=).)+$)([^&]*)/)[3];
It works against all of your examples, though I imagine it's horribly inefficient.
This question already has answers here:
How can you encode a string to Base64 in JavaScript?
(33 answers)
Closed 1 year ago.
Are there any methods in JavaScript that could be used to encode and decode a string using base64 encoding?
Some browsers such as Firefox, Chrome, Safari, Opera and IE10+ can handle Base64 natively. Take a look at this Stackoverflow question. It's using btoa() and atob() functions.
For server-side JavaScript (Node), you can use Buffers to decode.
If you are going for a cross-browser solution, there are existing libraries like CryptoJS or code like:
http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html (Archive)
With the latter, you need to thoroughly test the function for cross browser compatibility. And error has already been reported.
Internet Explorer 10+
// Define the string
var string = 'Hello World!';
// Encode the String
var encodedString = btoa(string);
console.log(encodedString); // Outputs: "SGVsbG8gV29ybGQh"
// Decode the String
var decodedString = atob(encodedString);
console.log(decodedString); // Outputs: "Hello World!"
Cross-Browser
Re-written and modularized UTF-8 and Base64 Javascript Encoding and Decoding Libraries / Modules for AMD, CommonJS, Nodejs and Browsers. Cross-browser compatible.
with Node.js
Here is how you encode normal text to base64 in Node.js:
//Buffer() requires a number, array or string as the first parameter, and an optional encoding type as the second parameter.
// Default is utf8, possible encoding types are ascii, utf8, ucs2, base64, binary, and hex
var b = Buffer.from('JavaScript');
// If we don't use toString(), JavaScript assumes we want to convert the object to utf8.
// We can make it convert to other formats by passing the encoding type to toString().
var s = b.toString('base64');
And here is how you decode base64 encoded strings:
var b = Buffer.from('SmF2YVNjcmlwdA==', 'base64')
var s = b.toString();
with Dojo.js
To encode an array of bytes using dojox.encoding.base64:
var str = dojox.encoding.base64.encode(myByteArray);
To decode a base64-encoded string:
var bytes = dojox.encoding.base64.decode(str)
bower install angular-base64
<script src="bower_components/angular-base64/angular-base64.js"></script>
angular
.module('myApp', ['base64'])
.controller('myController', [
'$base64', '$scope',
function($base64, $scope) {
$scope.encoded = $base64.encode('a string');
$scope.decoded = $base64.decode('YSBzdHJpbmc=');
}]);
But How?
If you would like to learn more about how base64 is encoded in general, and in JavaScript in-particular, I would recommend this article: Computer science in JavaScript: Base64 encoding
In Gecko/WebKit-based browsers (Firefox, Chrome and Safari) and Opera, you can use btoa() and atob().
Original answer: How can you encode a string to Base64 in JavaScript?
Here is a tightened up version of Sniper's post. It presumes well formed base64 string with no carriage returns. This version eliminates a couple of loops, adds the &0xff fix from Yaroslav, eliminates trailing nulls, plus a bit of code golf.
decodeBase64 = function(s) {
var e={},i,b=0,c,x,l=0,a,r='',w=String.fromCharCode,L=s.length;
var A="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for(i=0;i<64;i++){e[A.charAt(i)]=i;}
for(x=0;x<L;x++){
c=e[s.charAt(x)];b=(b<<6)+c;l+=6;
while(l>=8){((a=(b>>>(l-=8))&0xff)||(x<(L-2)))&&(r+=w(a));}
}
return r;
};
Short and fast Base64 JavaScript Decode Function without Failsafe:
function decode_base64 (s)
{
var e = {}, i, k, v = [], r = '', w = String.fromCharCode;
var n = [[65, 91], [97, 123], [48, 58], [43, 44], [47, 48]];
for (z in n)
{
for (i = n[z][0]; i < n[z][1]; i++)
{
v.push(w(i));
}
}
for (i = 0; i < 64; i++)
{
e[v[i]] = i;
}
for (i = 0; i < s.length; i+=72)
{
var b = 0, c, x, l = 0, o = s.substring(i, i+72);
for (x = 0; x < o.length; x++)
{
c = e[o.charAt(x)];
b = (b << 6) + c;
l += 6;
while (l >= 8)
{
r += w((b >>> (l -= 8)) % 256);
}
}
}
return r;
}
function b64_to_utf8( str ) {
return decodeURIComponent(escape(window.atob( str )));
}
https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64/Base64_encoding_and_decoding#The_.22Unicode_Problem.22
Modern browsers have built-in javascript functions for Base64 encoding btoa() and decoding atob(). More info about support in older browser versions: https://caniuse.com/?search=atob
However, be aware that atob and btoa functions work only for ASCII charset.
If you need Base64 functions for UTF-8 charset, you can do it with:
function base64_encode(s) {
return btoa(unescape(encodeURIComponent(s)));
}
function base64_decode(s) {
return decodeURIComponent(escape(atob(s)));
}
Did someone say code golf? =)
The following is my attempt at improving my handicap while catching up with the times. Supplied for your convenience.
function decode_base64(s) {
var b=l=0, r='',
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
s.split('').forEach(function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
});
return r;
}
What I was actually after was an asynchronous implementation and to my surprise it turns out forEach as opposed to JQuery's $([]).each method implementation is very much synchronous.
If you also had such crazy notions in mind a 0 delay window.setTimeout will run the base64 decode asynchronously and execute the callback function with the result when done.
function decode_base64_async(s, cb) {
setTimeout(function () { cb(decode_base64(s)); }, 0);
}
#Toothbrush suggested "index a string like an array", and get rid of the split. This routine seems really odd and not sure how compatible it will be, but it does hit another birdie so lets have it.
function decode_base64(s) {
var b=l=0, r='',
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
[].forEach.call(s, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
});
return r;
}
While trying to find more information on JavaScript string as array I stumbled on this pro tip using a /./g regex to step through a string. This reduces the code size even more by replacing the string in place and eliminating the need of keeping a return variable.
function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':String.fromCharCode((b>>>(l-=8))&0xff);
});
}
If however you were looking for something a little more traditional perhaps the following is more to your taste.
function decode_base64(s) {
var b=l=0, r='', s=s.split(''), i,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
for (i in s) {
b=(b<<6)+m.indexOf(s[i]); l+=6;
if (l>=8) r+=String.fromCharCode((b>>>(l-=8))&0xff);
}
return r;
}
I didn't have the trailing null issue so this was removed to remain under par but it should easily be resolved with a trim() or a trimRight() if you'd prefer, should this pose a problem for you.
ie.
return r.trimRight();
Note:
The result is an ascii byte string, if you need unicode the easiest is to escape the byte string which can then be decoded with decodeURIComponent to produce the unicode string.
function decode_base64_usc(s) {
return decodeURIComponent(escape(decode_base64(s)));
}
Since escape is being deprecated we could change our function to support unicode directly without the need for escape or String.fromCharCode we can produce a % escaped string ready for URI decoding.
function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}
Edit for #Charles Byrne:
Can't remember why we didn't ignore the '=' padding characters, might've worked with a specification that didn't require them at the time. If we were to modify the decodeURIComponent routine to ignore these, as we should since they do not represent any data, the result decodes the example correctly.
function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/=*$/,'').replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}
Now calling decode_base64('4pyTIMOgIGxhIG1vZGU=') will return the encoded string '✓ à la mode', without any errors.
Since '=' is reserved as padding character I can reduce my code golf handicap, if I may:
function decode_base64(s) {
var b=l=0,
m='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
return decodeURIComponent(s.replace(/./g, function (v) {
b=(b<<6)+m.indexOf(v); l+=6;
return l<8||'='==v?'':'%'+(0x100+((b>>>(l-=8))&0xff)).toString(16).slice(-2);
}));
}
nJoy!
The php.js project has JavaScript implementations of many of PHP's functions. base64_encode and base64_decode are included.
For what it's worth, I got inspired by the other answers and wrote a small utility which calls the platform specific APIs to be used universally from either Node.js or a browser:
/**
* Encode a string of text as base64
*
* #param data The string of text.
* #returns The base64 encoded string.
*/
function encodeBase64(data: string) {
if (typeof btoa === "function") {
return btoa(data);
} else if (typeof Buffer === "function") {
return Buffer.from(data, "utf-8").toString("base64");
} else {
throw new Error("Failed to determine the platform specific encoder");
}
}
/**
* Decode a string of base64 as text
*
* #param data The string of base64 encoded text
* #returns The decoded text.
*/
function decodeBase64(data: string) {
if (typeof atob === "function") {
return atob(data);
} else if (typeof Buffer === "function") {
return Buffer.from(data, "base64").toString("utf-8");
} else {
throw new Error("Failed to determine the platform specific decoder");
}
}
I have tried the Javascript routines at phpjs.org and they have worked well.
I first tried the routines suggested in the chosen answer by Ranhiru Cooray - http://ntt.cc/2008/01/19/base64-encoder-decoder-with-javascript.html
I found that they did not work in all circumstances. I wrote up a test case where these routines fail and posted them to GitHub at:
https://github.com/scottcarter/base64_javascript_test_data.git
I also posted a comment to the blog post at ntt.cc to alert the author (awaiting moderation - the article is old so not sure if comment will get posted).
Frontend: Good solutions above, but quickly for the backend...
NodeJS - no deprecation
Use Buffer.from.
> inBase64 = Buffer.from('plain').toString('base64')
'cGxhaW4='
> // DEPRECATED //
> new Buffer(inBase64, 'base64').toString()
'plain'
> (node:1188987) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
(Use `node --trace-deprecation ...` to show where the warning was created)
// Works //
> Buffer.from(inBase64, 'base64').toString()
'plain'
In Node.js we can do it in simple way
var base64 = 'SGVsbG8gV29ybGQ='
var base64_decode = new Buffer(base64, 'base64').toString('ascii');
console.log(base64_decode); // "Hello World"
I'd rather use the bas64 encode/decode methods from CryptoJS, the most popular library for standard and secure cryptographic algorithms implemented in JavaScript using best practices and patterns.
For JavaScripts frameworks where there is no atob method and in case you do not want to import external libraries, this is short function that does it.
It would get a string that contains Base64 encoded value and will return a decoded array of bytes (where the array of bytes is represented as array of numbers where each number is an integer between 0 and 255 inclusive).
function fromBase64String(str) {
var alpha =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var value = [];
var index = 0;
var destIndex = 0;
var padding = false;
while (true) {
var first = getNextChr(str, index, padding, alpha);
var second = getNextChr(str, first .nextIndex, first .padding, alpha);
var third = getNextChr(str, second.nextIndex, second.padding, alpha);
var fourth = getNextChr(str, third .nextIndex, third .padding, alpha);
index = fourth.nextIndex;
padding = fourth.padding;
// ffffffss sssstttt ttffffff
var base64_first = first.code == null ? 0 : first.code;
var base64_second = second.code == null ? 0 : second.code;
var base64_third = third.code == null ? 0 : third.code;
var base64_fourth = fourth.code == null ? 0 : fourth.code;
var a = (( base64_first << 2) & 0xFC ) | ((base64_second>>4) & 0x03);
var b = (( base64_second<< 4) & 0xF0 ) | ((base64_third >>2) & 0x0F);
var c = (( base64_third << 6) & 0xC0 ) | ((base64_fourth>>0) & 0x3F);
value [destIndex++] = a;
if (!third.padding) {
value [destIndex++] = b;
} else {
break;
}
if (!fourth.padding) {
value [destIndex++] = c;
} else {
break;
}
if (index >= str.length) {
break;
}
}
return value;
}
function getNextChr(str, index, equalSignReceived, alpha) {
var chr = null;
var code = 0;
var padding = equalSignReceived;
while (index < str.length) {
chr = str.charAt(index);
if (chr == " " || chr == "\r" || chr == "\n" || chr == "\t") {
index++;
continue;
}
if (chr == "=") {
padding = true;
} else {
if (equalSignReceived) {
throw new Error("Invalid Base64 Endcoding character \""
+ chr + "\" with code " + str.charCodeAt(index)
+ " on position " + index
+ " received afer an equal sign (=) padding "
+ "character has already been received. "
+ "The equal sign padding character is the only "
+ "possible padding character at the end.");
}
code = alpha.indexOf(chr);
if (code == -1) {
throw new Error("Invalid Base64 Encoding character \""
+ chr + "\" with code " + str.charCodeAt(index)
+ " on position " + index + ".");
}
}
break;
}
return { character: chr, code: code, padding: padding, nextIndex: ++index};
}
Resources used: RFC-4648 Section 4
Base64 Win-1251 decoding for encodings other than acsi or iso-8859-1.
As it turned out, all the scripts I saw here convert Cyrillic Base64 to iso-8859-1 encoding. It is strange that no one noticed this.
Thus, to restore the Cyrillic alphabet, it is enough to do an additional transcoding of the text from iso-8859-1 to windows-1251.
I think that with other languages, it will be the same. Just change Cyrilic windows-1251 to yours.
... and Thanks to Der Hochstapler for his code i'm take from his comment ... of over comment, which is somewhat unusual.
code for JScript (for Windows desktop only) (ActiveXObject) - 1251 file encoding
decode_base64=function(f){var g={},b=65,d=0,a,c=0,h,e="",k=String.fromCharCode,l=f.length;for(a="";91>b;)a+=k(b++);a+=a.toLowerCase()+"0123456789+/";for(b=0;64>b;b++)g[a.charAt(b)]=b;for(a=0;a<l;a++)for(b=g[f.charAt(a)],d=(d<<6)+b,c+=6;8<=c;)((h=d>>>(c-=8)&255)||a<l-2)&&(e+=k(h));return e};
sDOS2Win = function(sText, bInsideOut) {
var aCharsets = ["iso-8859-1", "windows-1251"];
sText += "";
bInsideOut = bInsideOut ? 1 : 0;
with (new ActiveXObject("ADODB.Stream")) { //http://www.w3schools.com/ado/ado_ref_stream.asp
type = 2; //Binary 1, Text 2 (default)
mode = 3; //Permissions have not been set 0, Read-only 1, Write-only 2, Read-write 3,
//Prevent other read 4, Prevent other write 8, Prevent other open 12, Allow others all 16
charset = aCharsets[bInsideOut];
open();
writeText(sText);
position = 0;
charset = aCharsets[1 - bInsideOut];
return readText();
}
}
var base64='0PPx8ero5SDh8+ru4uroIQ=='
text = sDOS2Win(decode_base64(base64), false );
WScript.Echo(text)
var x=WScript.StdIn.ReadLine();