Reputation: 6463
I have an array of bytes that I would to to encode to a string to pass to btoa
in the browser. These bytes use the full 0-255 range. I encountered what at first seemed to be a bug with btoa
, but it turns out to be a bug (or at least quite unexpected behavior) with javascript's Array.prototype.join. To illustrate the problem, I'll start with some base64-encoded data:
gACJNqQ0cg==
This can be decoded to a byte array as follows:
atob('gACJNqQ0cg==').split('').map(c => c.charCodeAt(0))
> [128, 0, 137, 54, 164, 52, 114]
Now, you would expect to be able to reverse the operation and get back the original string:
btoa([128, 0, 137, 54, 164, 52, 114].map(String.fromCharCode).join(''))
But instead, you get a much larger string:
gAAAAAEAiQIANgMApAQANAUAcgYA
Upon further investigation, the problem occurs when joining any strings created with String.fromCharCode:
'Hi'.split('').join('').length
> 2
'Hi'.split('').map(c => c.charCodeAt(0))
> [72, 105]
[72, 105].map(String.fromCharCode).join('').length
> 6
//what?
I see this behavior everywhere I have tried it: Chrome (60), Firefox (53), and Node (6.9.4). In the browser, you don't have simple alternatives such as node's
new Buffer(array, 'binary').toString('base64')
to work around this problem. How can I safely create a string from an array of byte values, which can be passed to btoa
?
Upvotes: 0
Views: 577
Reputation: 214967
Your code works for me if you specify an arrow function in map
instead of directly passing the String.fromCharCode
method to it:
console.log(btoa([128, 0, 137, 54, 164, 52, 114].map(x => String.fromCharCode(x)).join('')));
Upvotes: 1
Reputation: 6463
I found a simple workaround to this complicated problem: String concatenation. Here's an example:
let str = '';
[128, 0, 137, 54, 164, 52, 114].forEach(c => {
str += String.fromCharCode(c);
});
str.length
> 7
btoa(str)
>
).join('').length
It works, and it should perform well enough for strings that aren't huge. But I would love to see a better, cleaner, solution, or even just to understand more fully what's going on here with String.fromCharCode and Array.prototype.join.
Upvotes: 0