Support alternative b64 characters
Coincidentally fixes #2 and fixes #7.
This commit is contained in:
parent
353937e3a1
commit
0e148a48ef
72
index.html
72
index.html
|
@ -55,7 +55,7 @@
|
||||||
<a href="https://git.fwdekker.com/FWDekker/converter/src/branch/master/LICENSE">MIT License</a>.
|
<a href="https://git.fwdekker.com/FWDekker/converter/src/branch/master/LICENSE">MIT License</a>.
|
||||||
Source code available on <a href="https://git.fwdekker.com/FWDekker/converter/">git</a>.
|
Source code available on <a href="https://git.fwdekker.com/FWDekker/converter/">git</a>.
|
||||||
|
|
||||||
<div style="float: right;">v1.4.4</div>
|
<div style="float: right;">v1.4.5</div>
|
||||||
</section>
|
</section>
|
||||||
</footer>
|
</footer>
|
||||||
</main>
|
</main>
|
||||||
|
@ -66,11 +66,40 @@
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.44/BigInteger.min.js"
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/big-integer/1.6.44/BigInteger.min.js"
|
||||||
integrity="sha256-es+ex6Oj344uak+VnCPyaHY2nzQkqhr7ByWVQgdjATA=" crossorigin="anonymous"></script>
|
integrity="sha256-es+ex6Oj344uak+VnCPyaHY2nzQkqhr7ByWVQgdjATA=" crossorigin="anonymous"></script>
|
||||||
<script>
|
<script>
|
||||||
const stringReplaceAt =
|
/**
|
||||||
(str, index, replacement) => str.substr(0, index) + replacement + str.substr(index + replacement.length);
|
* Replaces the character at the given index with the given replacement.
|
||||||
|
*
|
||||||
|
* @param str the string to replace in
|
||||||
|
* @param index the index in the given string to replace at
|
||||||
|
* @param replacement the replacement to insert into the string
|
||||||
|
* @returns {string} the input string with one character replaced
|
||||||
|
*/
|
||||||
|
const stringReplaceAt = (str, index, replacement) =>
|
||||||
|
str.substr(0, index) + replacement + str.substr(index + replacement.length);
|
||||||
|
|
||||||
const stringReplaceAll =
|
/**
|
||||||
(str, target, replacement) => str.split(target).join(replacement);
|
* Replaces all instances of the target with the replacement.
|
||||||
|
*
|
||||||
|
* @param str the string to replace in
|
||||||
|
* @param target the character to replace
|
||||||
|
* @param replacement the replacement to insert into the string
|
||||||
|
* @returns {string} the input string with all instances of the target replaced
|
||||||
|
*/
|
||||||
|
const stringReplaceAll = (str, target, replacement) =>
|
||||||
|
str.split(target).join(replacement);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs `stringReplaceAll` for each character in `targets` and `replacements`.
|
||||||
|
*
|
||||||
|
* @param str the string to replace in
|
||||||
|
* @param targets the characters to replace
|
||||||
|
* @param replacements the replacements to insert into the string; each character here corresponds to a character
|
||||||
|
* in the targets string
|
||||||
|
* @returns {string} the input string with all instances of the targets replaced
|
||||||
|
*/
|
||||||
|
const stringReplaceAlls = (str, targets, replacements) =>
|
||||||
|
Array.from(targets).reduce((output, target, index) =>
|
||||||
|
stringReplaceAll(output, target, replacements[index]), str);
|
||||||
|
|
||||||
|
|
||||||
class NumeralSystem {
|
class NumeralSystem {
|
||||||
|
@ -117,7 +146,7 @@
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
this.textarea.value = this.numeralSystem.filterBaseString(this.textarea.value);
|
||||||
updateAllInputs(this.numeralSystem.baseToDecimal(this.textarea.value));
|
updateAllInputs(this, this.numeralSystem.baseToDecimal(this.textarea.value));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +162,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
class Base64NumeralSystem extends NumeralSystem {
|
class Base64NumeralSystem extends NumeralSystem {
|
||||||
|
// TODO Convert static methods to static properties once supported by Firefox
|
||||||
|
static defaultAlphabet() {
|
||||||
|
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new base 64 numeral system.
|
||||||
|
*
|
||||||
|
* @param alphabet the 64 characters to encode numbers with, and the padding character at the end
|
||||||
|
*/
|
||||||
constructor(alphabet) {
|
constructor(alphabet) {
|
||||||
super(64, alphabet, true);
|
super(64, alphabet, true);
|
||||||
}
|
}
|
||||||
|
@ -148,11 +188,14 @@
|
||||||
.map(pair => String.fromCharCode(parseInt(pair.join(""), 16)))
|
.map(pair => String.fromCharCode(parseInt(pair.join(""), 16)))
|
||||||
.join("");
|
.join("");
|
||||||
|
|
||||||
return btoa(b64);
|
return stringReplaceAlls(btoa(b64), Base64NumeralSystem.defaultAlphabet(), this.alphabet);
|
||||||
}
|
}
|
||||||
|
|
||||||
baseToDecimal(baseString) {
|
baseToDecimal(baseString) {
|
||||||
const hex = Array.from(atob(baseString))
|
if (baseString.length % 4 === 1) throw new Error("Invalid input string length.");
|
||||||
|
|
||||||
|
const normalBaseString = stringReplaceAlls(baseString, this.alphabet, Base64NumeralSystem.defaultAlphabet());
|
||||||
|
const hex = Array.from(atob(normalBaseString))
|
||||||
.map(char => char.charCodeAt(0).toString(16).padStart(2, "0")).join("");
|
.map(char => char.charCodeAt(0).toString(16).padStart(2, "0")).join("");
|
||||||
return bigInt(hex, 16);
|
return bigInt(hex, 16);
|
||||||
}
|
}
|
||||||
|
@ -160,17 +203,13 @@
|
||||||
|
|
||||||
class Base64NumeralSystemInput extends NumeralSystemInput {
|
class Base64NumeralSystemInput extends NumeralSystemInput {
|
||||||
// TODO Convert static methods to static properties once supported by Firefox
|
// TODO Convert static methods to static properties once supported by Firefox
|
||||||
static defaultAlphabet() {
|
|
||||||
return "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
||||||
}
|
|
||||||
|
|
||||||
static dropdownOptions() {
|
static dropdownOptions() {
|
||||||
return {"Standard": ['+', '/'], "Filename": ['-', '_'], "IMAP": ['+', ',']};
|
return {"Standard": ['+', '/'], "Filename": ['-', '_'], "IMAP": ['+', ',']};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
constructor(name) {
|
constructor(name) {
|
||||||
super(name, new Base64NumeralSystem(Base64NumeralSystemInput.defaultAlphabet()));
|
super(name, new Base64NumeralSystem(Base64NumeralSystem.defaultAlphabet()));
|
||||||
|
|
||||||
this.dropdownLabel = document.createElement("label");
|
this.dropdownLabel = document.createElement("label");
|
||||||
this.dropdownLabel.setAttribute("for", `${this.name}Dropdown`);
|
this.dropdownLabel.setAttribute("for", `${this.name}Dropdown`);
|
||||||
|
@ -236,9 +275,10 @@
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
const updateAllInputs = newValue => {
|
const updateAllInputs = (source, newValue) => {
|
||||||
for (const input of inputs)
|
for (const input of inputs)
|
||||||
input.update(newValue);
|
if (input !== source)
|
||||||
|
input.update(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -248,7 +288,7 @@
|
||||||
for (const input of inputs)
|
for (const input of inputs)
|
||||||
input.addToParent(inputParent);
|
input.addToParent(inputParent);
|
||||||
|
|
||||||
updateAllInputs(bigInt(42));
|
updateAllInputs(undefined, bigInt(42));
|
||||||
inputs[0].textarea.focus();
|
inputs[0].textarea.focus();
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in New Issue