367

Are there any methods in JavaScript that could be used to encode and decode a string using base64 encoding?

Mo.
  • 40,243
  • 37
  • 86
  • 131
  • If you need the binary data as really binary data: https://stackoverflow.com/questions/21797299/convert-base64-string-to-arraybuffer – tschumann Aug 20 '21 at 07:15

16 Answers16

275

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.

Andy Gee
  • 3,149
  • 2
  • 29
  • 44
Ranhiru Jude Cooray
  • 19,542
  • 20
  • 83
  • 128
  • 1
    I used this method to encode a SVG in base64 with the Date URI scheme. Surprise: this function urlencodes every character, so I get this malformed XML at target: %3C%3Fxml%20version%3D%271.0%27%20%3F%3E%3Csvg%20xmlns%3D%27http%... – Dereckson Feb 13 '13 at 19:50
  • 38
    Node.js can do Base64 natively: `new Buffer('Hello, world!').toString('base64');` `new Buffer('SGVsbG8sIHdvcmxkIQ==', 'base64').toString('ascii');` [(source)](http://stackoverflow.com/a/6182519/492203) – alexia Jul 09 '14 at 09:12
  • And if I wanted to do it URL-safe? – Snackoverflow Sep 18 '19 at 10:01
  • 10
    in node 5+, use Buffer.from, as `new Buffer(string)` is deprecated. `Buffer.from(jwt.split('.')[1], 'base64').toString()` – Ray Foss Oct 09 '19 at 18:46
  • replace Buffer with Buffer.from as Buffer is now deprecated – Shalabyer Apr 06 '22 at 23:31
  • `atob()` and `btoa()` are only provided for compatibility with legacy web platform APIs and should never be used in new code, because they use strings to represent binary data and predate the introduction of typed arrays in JavaScript. For code running using Node.js APIs, converting between base64-encoded strings and binary data should be performed using `Buffer.from(str, 'base64')` and `buf.toString('base64')`. – Felix Haeberle May 27 '22 at 11:58
  • @FelixHaeberle, unfortunately your comment doesn't add any value, you are saying they shouldn't be used "in client javascript" then you go ahead and give alternative solution for server side! – AaA Mar 09 '23 at 02:08
115

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

Leonardo Alves Machado
  • 2,747
  • 10
  • 38
  • 53
davidcondrey
  • 34,416
  • 17
  • 114
  • 136
  • 2
    FYI: The cross-browser version has some nasty leaks with `c2` and likely `c1` and `c3` so it will not work with `"use strict"` as defined above. – Campbeln Jan 07 '15 at 04:19
  • Using Node js I reduced to: `new Buffer('SmF2YVNjcmlwdA==', 'base64').toString()`. Is there any specific reason to not do that? – Lucas Andrade Jul 24 '20 at 13:32
  • 1
    I know this is an old answer, but `new Buffer()` seems to be deprecated. For the new viewers like myself, `Buffer.from()` should achieve the same result like @ecoologic's response [below](https://stackoverflow.com/a/68311695/13211675) – grkmk Aug 17 '21 at 11:53
67

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?

Community
  • 1
  • 1
alexia
  • 14,440
  • 8
  • 42
  • 52
  • This is a life saver. I used a few different implementations to decode very big base64 encoded strings and the result was always wrong. atob() works great! – b2238488 Aug 01 '11 at 20:42
  • 15
    Small nitpick: Opera isn't based on Gecko or Webkit, it uses its own rendering engine called Presto. – Peter Olson Apr 07 '12 at 13:29
  • Wow, thanks for this. Didn't know there was a native base64 encoder in these browsers! – Rob Porter Oct 11 '12 at 18:00
  • 5
    @PeterOlson Not anymore :) – Mustafa Nov 18 '13 at 22:34
  • @Mustafa Does Opera use Webkit now? – Peter Olson Nov 19 '13 at 03:25
  • @PeterOlson yes, they use Blink (fork of WebKit) as Google – Mustafa Nov 19 '13 at 19:33
  • 1
    I realize this is an old post, but about the concern of @b2238488, you can split the base64 string so that each token's length is a multiple of 4, and decode them separately. The result will be the same as decoding the entire string at once. – alexia Dec 09 '13 at 14:54
  • As of November 2014, btoa() and atob() are now supported in all modern browsers, including IE10+ http://caniuse.com/#search=btoa – EricP Nov 14 '14 at 02:13
49

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;
};
broc.seib
  • 21,643
  • 8
  • 63
  • 62
  • 5
    Even less bytes ;D `decodeBase64=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>>(c-=8)&255)||a – Oliver Salzburg Apr 30 '15 at 14:19
  • Yeah but works only with ASCII. Cyr characters get mangled for example. – Martin Kovachev Sep 17 '15 at 09:54
  • @MartinKovachev can you post a new comment with example text with Cyr chars and the corresponding base64 encoding? Maybe we can fix the code to accommodate. – broc.seib Sep 17 '15 at 18:41
  • Here: something like that: тестова фраза – Martin Kovachev Sep 18 '15 at 03:16
  • 3
    @OliverSalzburg Even less generate code table :) : `var g={},k=String.fromCharCode,i;for(i=0;i<64;)g[k(i>61?(i&1)*4|43:i+[65,71,-4][i/26&3])]=i++;` – Mike Jan 11 '16 at 22:58
37

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;
}
msrd0
  • 7,816
  • 9
  • 47
  • 82
Sniper
  • 371
  • 2
  • 2
  • 7
    Opera 11.62 seems to have problem with '%256' part. Replacing it with '&0xff' makes it work. – Yaroslav Stavnichiy May 01 '12 at 12:53
  • Tyk virtual endpoint javascript code seems to have problem with '\x00' part. Replacing it with r = r.replace(/\x00/g, '') make it work – Panup Pong Feb 14 '20 at 05:57
  • Thanks! Wanted to decode LoRaWAN encoded data. Working fine with 'atob()' or 'Buffer.from' on my PC, but ThingsBoard' 'Rule Chain' could not recognize any one of them. This function working fine. – Fakir May 12 '22 at 10:10
16

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

PPB
  • 2,937
  • 3
  • 17
  • 12
  • "escape" is deprecated: https://www.ecma-international.org/ecma-262/9.0/index.html#sec-additional-ecmascript-features-for-web-browsers – David Braun Oct 20 '19 at 13:47
14

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)));
}
D Cruse
  • 397
  • 3
  • 7
  • Thank you! This was very nice and simple – sebasira Jun 22 '21 at 14:14
  • Thanks for this simple solution. FYI, the [escape](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/escape) and [unescape](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/unescape) functions are now deprecated. I just removed them from the examples above and they worked fine. – miker Jul 28 '23 at 18:06
12

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!

nickl-
  • 8,417
  • 4
  • 42
  • 56
  • 3
    You don't need to `split` the string, since you can index a JavaScript string like an array. `s.split('').forEach(function ...` can be replaced by `[].forEach.call(s, function ...`. It should be a lot faster, due to it not having to split the string. – Toothbrush Jul 28 '14 at 19:41
  • The "more traditional" one was completely broken for me - produced a garbled mess with traces of original text sprinkled throughout. On Chrome. – Steve Bennett Jun 02 '15 at 23:32
  • @Steve Bennett I tested all variants in chrome... it works. Can you provide an example base64 string that fails? – nickl- May 10 '18 at 06:03
  • Three years later? Ha. I don't even remember what I needed this for. – Steve Bennett May 10 '18 at 13:48
  • '✓ à la mode' will break it. Unicode/UTF-8 characters are a headache unless you use escape (decodeURIComponent(escape(atob(s))) . People are cutting and pasting unicode from various sources or data is coming from non-html sources. My workaround is use escape with fallback shim function for escape or just decoding the base64 string with c# (with cross site scripting security caveat of course). For me it depends on the string destination. It may be for html, xml, pdf, email, database or combination. SQL 2019 supports UTF8, but we are on 2016 and legacy 2008 so db storage is Base64 string. – Charles Byrne Oct 04 '21 at 15:08
  • 1
    @CharlesByrne Wow, been a while, interesting to rehash the past, clean forgot about this, been using `atob` and `btoa` myself of late. You could also remove the padding characters yourself but the above edit will resolve. Seems completely deprecating `escape` becomes less likely as the specification evolves. – nickl- Oct 05 '21 at 19:36
11

The php.js project has JavaScript implementations of many of PHP's functions. base64_encode and base64_decode are included.

ceejayoz
  • 176,543
  • 40
  • 303
  • 368
  • 1
    php.js is the incarnation of all evil and belongs to its own layer in hell. Avoid it like the plague. (More info: https://softwareengineering.stackexchange.com/questions/126671/is-it-considered-bad-practice-to-have-php-in-your-javascript) – Coreus Apr 03 '19 at 11:51
  • 1
    I don't see much supporting that blanket assertion in that link, @Coreus. Used judiciously, or as a starting point, it's a perfectly acceptable way to figure out the equivalent logic in JS for something you might already know how to do in PHP. – ceejayoz Apr 03 '19 at 12:13
11

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");
    }
}
kraenhansen
  • 1,535
  • 2
  • 15
  • 26
6

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).

Scott Carter
  • 1,254
  • 9
  • 16
4

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'
ecoologic
  • 10,202
  • 3
  • 62
  • 66
3

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"
KARTHIKEYAN.A
  • 18,210
  • 6
  • 124
  • 133
1

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.

Dan Dascalescu
  • 143,271
  • 52
  • 317
  • 404
0

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

Community
  • 1
  • 1
0

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();
Garric
  • 591
  • 3
  • 10