Strange use of "for" cycle in Javascript, please explain - javascript

I found this strange JavaScript I cannot understand. The for cycle has a strange syntax (many parameters), can you explain me how it is intended to work? Thanks
decode: function(s){
for(var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt"; ++i < l;
((a = s[i][c](0)) & 0x80) &&
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")
);
return s.join("");
}

That's an ordinary for loop, but with a very long var statement in the first part.
It's just like
var a, b, c;
Also the iterator statement in the for loop contains a lot of operations instead of the loop actually having a body.
Either this function was written by a terrible programmer with no regard for readable code, or it has been intentionally minified and obfuscated.

interesting function, apparently trans-coding a certain set of chars, kind of esoteric and will only work with an ASCII code but here's the breakdown:
for (var i = 0; i < s.length; i++) {
var a = s.charCodeAt(i);
if (a & 0x80) { // (a >= 128) if extended ascii
var b = s.charCodeAt(i + 1);
var specialA = (a & 0xfc) === 0xc0; // a IS [À, Á, Â or Ã] essentially [192, 193, 194, 195]
var specialB = (b & 0xc0) === 0x80; // b >= 128 & b <= 191 eg. b is not a special Latin Ascii Letter
if (specialA && specialB) {
var txA = (a & 0x03) << 6; // [0, 64, 128, 192]
var txB = b & 0x3f; // 0 - 63
s[i] = String.fromCharCode(txA + txB);
} else {
s[i] = String.fromCharCode(128);
s[++i] = "";
}
}
}
hope this helps, either way i found the decoding interesting, reminds of reading raw assembler, lol -ck

The different parts of the for loop is all there, divided by the semicolons (;).
The var part:
var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt";
The check part:
++i < l;
The update part:
((a = s[i][c](0)) & 0x80) &&
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")
After the for() statement comes a ; right away, meaning that the loop doesn't have a body, but all the statements in the var-, check-, and update part will still be executed untill the check is no longer true.
Looks like someone didn't want their code to be readable. Where did you find it, anyway?

Breaking the loop into a one more readable:
rearranged loop parameters
changed (...)&&(...) with an if(...){(...)}
changed l to len
moved s = s.split(...) outside the len
.
var a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";
for(var i = -1, len = s.length; ++i < len;){
if((a = s[i][c](0)) & 0x80){
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ? o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "");
}
}
changed i initial value and how/where it increases
moved a = s[i][c](0) outside
.
var a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";
for(var i = 0, len = s.length; i < len; i++){
a = s[i][c](0);
if(a & 0x80){
s[i] = (a & 0xfc);
(s[i] == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ? o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "");
}
}
created tmp to make things easier to read
stored the ternary operation result in tmp
splitted (s[i] == 0xc0 && tmp, s[++i] = ""); with an
if(...){s[++i] = "";}
replaced the new loop inside the your example
.
decode: function(s){
var tmp, a, b, s = s.split(""), o = String.fromCharCode, c = "charCodeAt";
for(var i = 0, len = s.length; i < len; i++){
a = s[i][c](0);
if(a & 0x80){
s[i] = (a & 0xfc);
if(((b = s[i + 1][c](0)) & 0xc0) == 0x80){
tmp = o(((a & 0x03) << 6) + (b & 0x3f));
}else{
tmp = o(128);
}
if(s[i] == 0xc0 && tmp){
s[++i] = "";
}
}
}
return s.join("");
}
Final result /\

Related

How to understand Ternary JavaScript expression?

I'm bad with JS at now, especially with the operator "?"
And I'm trying to understand the following code.
Maybe it could be more friendly ?
So, if I don't want to use this operator, how can it be looks.
JavaScript code:
function(t) {
for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; )
(s = t.charCodeAt(i)) < 128 ? (n += String.fromCharCode(s),
i++) : s > 191 && s < 224 ? (a = t.charCodeAt(i + 1),
n += String.fromCharCode((31 & s) << 6 | 63 & a),
i += 2) : (a = t.charCodeAt(i + 1),
e = t.charCodeAt(i + 2),
n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
i += 3);
return n
}
It seems like this is same as:
function(t) {
for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; )
if((s = t.charCodeAt(i)) < 128) {
n += String.fromCharCode(s);
i++;
} else if(s > 191 && s < 224) {
a = t.charCodeAt(i + 1);
n += String.fromCharCode((31 & s) << 6 | 63 & a);
i += 2;
} else {
a = t.charCodeAt(i + 1);
e = t.charCodeAt(i + 2);
n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 |
63 & e);
i += 3;
}
return n
}
This is an overly complicated expression involving multiple ternary operators.
I think it should be simplified.
A ternary operator behaves like an if but it is an expression that returns one value out of 2 options, depending on the first operand.
For example:
operand ? valueIfTrue : valueIfFalse is a ternary expression that returns valueIfTrue if operand is "truthy" and returns valueIfFalse if operand is "falsey".
You can substitute any expression in place of valueIfTrue and valueIfFalse and this way you can get really complicated expressions, sometimes unnecessarily complex.
As an example of making expressions complicated, let's consider: For example: operand ? valueIfTrue : valueIfFalse
If we then replace valueIfTrue with another ternary operator, e.g. myOtherOperand ? myOtherIfTrue : myOtherIfFalse then the original expression becomes:
operand ? myOtherOperand ? myOtherIfTrue : myOtherIfFalse: valueIfFalse
This is not a nice way to write it, it can be improved like this, I just put parenthesis.
operand ? (myOtherOperand ? myOtherIfTrue : myOtherIfFalse) : valueIfFalse
It can be improved again by formatting like this:
operand
? myOtherOperand
? myOtherIfTrue // if both operand and myOtherOperand are true
: myOtherIfFalse // if operand is true and myOtherOperand is false
: valueIfFalse // this will be returned if operand is false
This shows that code formatting is essential for understanding it. But of course the first step is to have simple code. Anyways, here is how I would format the code in the question so it can be easier to understand:
function myFunction(t) {
for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r; ) {
(s = t.charCodeAt(i)) < 128
? (n += String.fromCharCode(s), i++)
: s > 191 && s < 224
? (a = t.charCodeAt(i + 1), n += String.fromCharCode((31 & s) << 6 | 63 & a), i += 2)
: (a = t.charCodeAt(i + 1),
e = t.charCodeAt(i + 2),
n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
i += 3); // end of ternary operators
return n;
}
}
Now it is clearer and we see statements separated by commas inside of the two ternary operators that are used. Commas are used to execute multiple things in the same expression, e.g. (n += String.fromCharCode(s), i++) will increase n and also i. In this case, it is better to move those outside of a ternary and into a normal if statement like this:
function myFunction(t) {
for (var e, r = t.length, n = "", i = 0, s = 0, a = 0; i < r;) {
const firstCheck = (s = t.charCodeAt(i)) < 128;
const secondCheck = s > 191 && s < 224;
if (firstCheck) {
n += String.fromCharCode(s);
i++;
} else if (secondCheck) {
// This is originally: (a = t.charCodeAt(i + 1), n += String.fromCharCode((31 & s) << 6 | 63 & a), i += 2);
a = t.charCodeAt(i + 1);
n += String.fromCharCode((31 & s) << 6 | 63 & a);
i += 2;
} else {
// this is originally:
// (a = t.charCodeAt(i + 1),
// e = t.charCodeAt(i + 2),
// n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e),
// i += 3);
a = t.charCodeAt(i + 1);
e = t.charCodeAt(i + 2);
n += String.fromCharCode((15 & s) << 12 | (63 & a) << 6 | 63 & e);
i += 3;
}
return n;
}
}
So basically break it down and take it step by step to understand it, then you can change it because you understand it.

Failed to decode base64 in javascript

I receive an id_token as part of my current href. It is encoded in base64. I try to decode it using atob(extractedIdToken), but get the following error:
Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded
When I copy and paste the extracted id_token in my code and go to an online decoding site, it decodes correctly. Do you have suggestion?
I always use this to decode and encode in Base64, try it
var Base64 = {
_keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
encode: function (e) {
var t = "";
var n, r, i, s, o, u, a;
var f = 0;
e = Base64._utf8_encode(e);
while (f < e.length) {
n = e.charCodeAt(f++);
r = e.charCodeAt(f++);
i = e.charCodeAt(f++);
s = n >> 2;
o = (n & 3) << 4 | r >> 4;
u = (r & 15) << 2 | i >> 6;
a = i & 63;
if (isNaN(r)) {
u = a = 64
} else if (isNaN(i)) {
a = 64
}
t = t + this._keyStr.charAt(s) + this._keyStr.charAt(o) + this._keyStr.charAt(u) + this._keyStr.charAt(a)
}
return t
},
decode: function (e) {
var t = "";
var n, r, i;
var s, o, u, a;
var f = 0;
e = e.replace(/[^A-Za-z0-9+/=]/g, "");
while (f < e.length) {
s = this._keyStr.indexOf(e.charAt(f++));
o = this._keyStr.indexOf(e.charAt(f++));
u = this._keyStr.indexOf(e.charAt(f++));
a = this._keyStr.indexOf(e.charAt(f++));
n = s << 2 | o >> 4;
r = (o & 15) << 4 | u >> 2;
i = (u & 3) << 6 | a;
t = t + String.fromCharCode(n);
if (u != 64) {
t = t + String.fromCharCode(r)
}
if (a != 64) {
t = t + String.fromCharCode(i)
}
}
t = Base64._utf8_decode(t);
return t
},
_utf8_encode: function (e) {
e = e.replace(/rn/g, "n");
var t = "";
for (var n = 0; n < e.length; n++) {
var r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r)
} else if (r > 127 && r < 2048) {
t += String.fromCharCode(r >> 6 | 192);
t += String.fromCharCode(r & 63 | 128)
} else {
t += String.fromCharCode(r >> 12 | 224);
t += String.fromCharCode(r >> 6 & 63 | 128);
t += String.fromCharCode(r & 63 | 128)
}
}
return t
},
_utf8_decode: function (e) {
var t = "";
var n = 0;
var r = c1 = c2 = 0;
while (n < e.length) {
r = e.charCodeAt(n);
if (r < 128) {
t += String.fromCharCode(r);
n++
} else if (r > 191 && r < 224) {
c2 = e.charCodeAt(n + 1);
t += String.fromCharCode((r & 31) << 6 | c2 & 63);
n += 2
} else {
c2 = e.charCodeAt(n + 1);
c3 = e.charCodeAt(n + 2);
t += String.fromCharCode((r & 15) << 12 | (c2 & 63) << 6 | c3 & 63);
n += 3
}
}
return t
}
};
Thanks all for your answers. I ended up moving the Base64 decoding process to the Java backend using the java package: java.util.Base64.
In my case, the issue was that the encoded string should have been treated as segments. Just separate the code with the separator "." or whatever your case is. Then, decode only the different parts separately. This resolved my issue and I was able to decode using window.atob(). Hope this helps.

Number Formatting for large integer numbers in Javascript

I know there are in-build function in javascript like toLocalString() to achieve number formatting. But this question is purely for learning and logic understanding.
I have a function in javascript that formats given number in Indian Number formatting standards (eg: 1,234 | 12,21,123 | etc)
Code
function formatter(input) {
var inputStr = input.toString(), l = inputStr.length;
var c = 1, f = 0;
console.log(l);
for (var x=l-1; x>=0; x--) {
if (x === 0) {
continue;
}
if (c === 3 && f === 0) {
inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x);
f = 1;
c = 0;
} else if (c % 2 === 0 && f === 1) {
inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x);
c = 0;
}
c++;
}
return inputStr;
}
Now this works for most part (as far as I have test, do point out bugs if you spot any). But my question is how do I handle large number in this, i.e. how do I handle values greater than 9007199254740991.
Hope this now fixes the issue:
function formatter(inputStr) {
inputStr+="";
let c = 1, f = 0;
for (let x=inputStr.length-1; x>=0; x--) {
if (x === 0) continue;
if (c === 3 && f === 0) {
inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x);
f = 1;
c = 0;
} else if (c % 2 === 0 && f === 1) {
inputStr = inputStr.substring(0, x) + ',' + inputStr.substring(x);
c = 0;
}
c++;
}
return inputStr;
}
//========= Tests =======
console.log(formatter(9007199254740991));
console.log(formatter("900719925474093454549341"));
console.log(formatter("123456678890987665443221112345667676766545434243"));

Convert html-input to proper encoding

I have a html-form with one html-input-field. The input is copied via clipboard from other programs. Sometimes the copied text is not utf-8, but ansi (tested with notepad++). Than, umlauts like ü are copied as ü.
As I don't want to change the encoding of the clipboard-text everytime (with i.e.notepad++), I would like to do this with javascript directly when parsing and spliting the input-text.
Is there a way to do this without implementing an own function for this (which would be the next thing I would do for the most common umlauts)?
Stealing from the internet this:
//+ Jonas Raoni Soares Silva
//# http://jsfromhell.com/geral/utf-8 [rev. #1]
var UTF8 = {
encode: function(s){
for(var c, i = -1, l = (s = s.split("")).length, o = String.fromCharCode; ++i < l;
s[i] = (c = s[i].charCodeAt(0)) >= 127 ? o(0xc0 | (c >>> 6)) + o(0x80 | (c & 0x3f)) : s[i]
);
return s.join("");
},
decode: function(s){
for(var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt"; ++i < l;
((a = s[i][c](0)) & 0x80) &&
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")
);
return s.join("");
}
};
You can then add your input:
<input type="text" id="test">
And listen to the PASTE event and, after a few milliseconds (else you will get "" as .val), you can replace the entire value of the input with the decoded one:
$('#test').on('paste', function(e) {
var controller = $(this);
setTimeout(function(){
controller.val(UTF8.decode(controller.val()));
},10);
});
Codepen:
http://codepen.io/anon/pen/GgYZeb
Please note that it is only listening to the PASTE event. You can also add other events if you're interested.

Javascript processing Cyrillic input

When i get a json feed from a Cyrillic site, the data is in a \ufffd format instead of Cyrillic chars.
(example feed: http://jsonduit.com/v1/f/l/7sg?cb=getJsonP_1284131679846_0)
So when i set the source html to the input, i get weird boxes instead of characters.
I tried to unescape the input but that wont work too.
How do i revert the feed back to Cyrillic?
(btw, the source page encoding is set to UTF-8)
decodeURIComponent("stringToDecodeToCyrillic")
Example:
decodeURIComponent("%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B5%D0%B9") === "Алексей"
Fastest way to encode cyrillic letters for url
It seems you receive UTF8 string. Use the following class to decode:
UTF8 = {
encode: function(s){
for(var c, i = -1, l = (s = s.split("")).length, o = String.fromCharCode; ++i < l;
s[i] = (c = s[i].charCodeAt(0)) >= 127 ? o(0xc0 | (c >>> 6)) + o(0x80 | (c & 0x3f)) : s[i]
);
return s.join("");
},
decode: function(s){
for(var a, b, i = -1, l = (s = s.split("")).length, o = String.fromCharCode, c = "charCodeAt"; ++i < l;
((a = s[i][c](0)) & 0x80) &&
(s[i] = (a & 0xfc) == 0xc0 && ((b = s[i + 1][c](0)) & 0xc0) == 0x80 ?
o(((a & 0x03) << 6) + (b & 0x3f)) : o(128), s[++i] = "")
);
return s.join("");
}
};
Usage:
var newString = UTF8.decode( yourString );

Categories