Files
smartstring/ts/smartstring.base64.ts

162 lines
4.5 KiB
TypeScript
Raw Permalink Normal View History

2016-11-01 00:22:38 +01:00
/**
* the type for base 64
*/
2022-09-13 19:13:04 +02:00
export type TStringInputType = 'string' | 'base64' | 'base64uri';
2016-11-01 00:22:38 +01:00
/**
* Cross-platform base64 implementation
* Works in both Node.js and browser environments
*/
const universalBase64 = {
encode: (str: string): string => {
if (typeof Buffer !== 'undefined') {
// Node.js environment
return Buffer.from(str, 'utf8').toString('base64');
} else if (typeof btoa !== 'undefined') {
// Browser environment
// Handle Unicode properly
const utf8Bytes = new TextEncoder().encode(str);
const binaryString = Array.from(utf8Bytes, byte => String.fromCharCode(byte)).join('');
return btoa(binaryString);
} else {
// Fallback pure JS implementation
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
const bytes = new TextEncoder().encode(str);
let result = '';
let i = 0;
while (i < bytes.length) {
const a = bytes[i++];
const b = i < bytes.length ? bytes[i++] : 0;
const c = i < bytes.length ? bytes[i++] : 0;
const bitmap = (a << 16) | (b << 8) | c;
result += chars.charAt((bitmap >> 18) & 63);
result += chars.charAt((bitmap >> 12) & 63);
result += i - 2 < bytes.length ? chars.charAt((bitmap >> 6) & 63) : '=';
result += i - 1 < bytes.length ? chars.charAt(bitmap & 63) : '=';
}
return result;
}
},
decode: (str: string): string => {
// Handle base64uri by converting back to standard base64
const base64String = str
.replace(/-/g, '+')
.replace(/_/g, '/')
.padEnd(str.length + ((4 - (str.length % 4)) % 4), '=');
if (typeof Buffer !== 'undefined') {
// Node.js environment
return Buffer.from(base64String, 'base64').toString('utf8');
} else if (typeof atob !== 'undefined') {
// Browser environment
const binaryString = atob(base64String);
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
return new TextDecoder().decode(bytes);
} else {
// Fallback pure JS implementation
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
let bytes: number[] = [];
let i = 0;
while (i < base64String.length) {
const encoded1 = chars.indexOf(base64String.charAt(i++));
const encoded2 = chars.indexOf(base64String.charAt(i++));
const encoded3 = chars.indexOf(base64String.charAt(i++));
const encoded4 = chars.indexOf(base64String.charAt(i++));
const bitmap = (encoded1 << 18) | (encoded2 << 12) | (encoded3 << 6) | encoded4;
bytes.push((bitmap >> 16) & 255);
if (encoded3 !== 64) bytes.push((bitmap >> 8) & 255);
if (encoded4 !== 64) bytes.push(bitmap & 255);
}
return new TextDecoder().decode(new Uint8Array(bytes));
}
}
};
2016-11-01 00:22:38 +01:00
/**
* handle base64 strings
*/
export class Base64 {
private refString: string;
2022-09-13 19:13:04 +02:00
constructor(inputStringArg, typeArg: TStringInputType) {
2017-10-05 15:55:59 +02:00
switch (typeArg) {
case 'string': // easiest case
this.refString = inputStringArg;
break;
2017-10-05 15:55:59 +02:00
case 'base64':
this.refString = base64.decode(inputStringArg);
break;
2017-10-05 15:55:59 +02:00
case 'base64uri':
this.refString = base64.decode(inputStringArg);
2016-11-01 00:22:38 +01:00
}
2017-10-05 15:55:59 +02:00
}
2016-11-01 00:22:38 +01:00
2017-10-05 15:55:59 +02:00
/**
* the simple string (unencoded)
*/
get simpleString() {
return this.refString;
2017-10-05 15:55:59 +02:00
}
2016-11-01 00:22:38 +01:00
2017-10-05 15:55:59 +02:00
/**
* the base64 encoded version of the original string
*/
get base64String() {
return base64.encode(this.refString);
2017-10-05 15:55:59 +02:00
}
2016-11-01 00:22:38 +01:00
2017-10-05 15:55:59 +02:00
/**
* the base64uri encoded version of the original string
*/
get base64UriString() {
return base64.encodeUri(this.refString);
2017-10-05 15:55:59 +02:00
}
}
export let base64 = {
2017-10-05 15:55:59 +02:00
/**
* encodes the string
*/
encode: (stringArg: string) => {
return universalBase64.encode(stringArg);
2017-10-05 15:55:59 +02:00
},
2017-10-05 15:55:59 +02:00
/**
* encodes a stringArg to base64 uri style
*/
encodeUri: (stringArg: string) => {
return universalBase64.encode(stringArg)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=/g, '');
2017-10-05 15:55:59 +02:00
},
2017-10-05 15:55:59 +02:00
/**
* decodes a base64 encoded string
*/
decode: (stringArg: string) => {
return universalBase64.decode(stringArg);
2020-12-31 03:56:40 +00:00
},
2022-09-13 19:23:11 +02:00
/**
*
* @param stringArg
* checks wether the string is base64 encoded
*/
isBase64: (stringArg: string) => {
const regex = /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)?$/;
return regex.test(stringArg);
},
};