2023-07-09 10:55:26 -04:00
|
|
|
// Implementation of https://github.com/meeb/phonobyte
|
2023-07-09 12:59:05 -04:00
|
|
|
import 'dart:convert';
|
2023-07-09 10:55:26 -04:00
|
|
|
import 'dart:typed_data';
|
2023-07-09 12:59:05 -04:00
|
|
|
import 'package:charcode/charcode.dart';
|
2023-07-09 10:55:26 -04:00
|
|
|
|
2023-07-09 12:59:05 -04:00
|
|
|
const _byteToPhono = [
|
2023-07-09 10:55:26 -04:00
|
|
|
'jab',
|
|
|
|
'tip',
|
|
|
|
'led',
|
|
|
|
'rut',
|
|
|
|
'dak',
|
|
|
|
'jig',
|
|
|
|
'rud',
|
|
|
|
'pub',
|
|
|
|
'not',
|
|
|
|
'kid',
|
|
|
|
'bid',
|
|
|
|
'gup',
|
|
|
|
'lep',
|
|
|
|
'juk',
|
|
|
|
'jib',
|
|
|
|
'sid',
|
|
|
|
'fon',
|
|
|
|
'dug',
|
|
|
|
'lap',
|
|
|
|
'sog',
|
|
|
|
'bug',
|
|
|
|
'ret',
|
|
|
|
'net',
|
|
|
|
'fip',
|
|
|
|
'gad',
|
|
|
|
'peg',
|
|
|
|
'gap',
|
|
|
|
'fet',
|
|
|
|
'rog',
|
|
|
|
'lob',
|
|
|
|
'lin',
|
|
|
|
'pip',
|
|
|
|
'fud',
|
|
|
|
'lag',
|
|
|
|
'gut',
|
|
|
|
'reb',
|
|
|
|
'din',
|
|
|
|
'sun',
|
|
|
|
'jun',
|
|
|
|
'dig',
|
|
|
|
'rag',
|
|
|
|
'neg',
|
|
|
|
'bin',
|
|
|
|
'ben',
|
|
|
|
'gob',
|
|
|
|
'run',
|
|
|
|
'fab',
|
|
|
|
'lit',
|
|
|
|
'ked',
|
|
|
|
'rug',
|
|
|
|
'lod',
|
|
|
|
'rib',
|
|
|
|
'rip',
|
|
|
|
'sod',
|
|
|
|
'ped',
|
|
|
|
'dip',
|
|
|
|
'leg',
|
|
|
|
'sib',
|
|
|
|
'sad',
|
|
|
|
'sat',
|
|
|
|
'pak',
|
|
|
|
'jet',
|
|
|
|
'bun',
|
|
|
|
'gon',
|
|
|
|
'geg',
|
|
|
|
'bit',
|
|
|
|
'gud',
|
|
|
|
'rig',
|
|
|
|
'dek',
|
|
|
|
'pot',
|
|
|
|
'pug',
|
|
|
|
'ken',
|
|
|
|
'gub',
|
|
|
|
'rid',
|
|
|
|
'pen',
|
|
|
|
'nep',
|
|
|
|
'gib',
|
|
|
|
'jot',
|
|
|
|
'pup',
|
|
|
|
'tid',
|
|
|
|
'sin',
|
|
|
|
'kin',
|
|
|
|
'job',
|
|
|
|
'ted',
|
|
|
|
'fun',
|
|
|
|
'fop',
|
|
|
|
'dan',
|
|
|
|
'nip',
|
|
|
|
'but',
|
|
|
|
'tun',
|
|
|
|
'put',
|
|
|
|
'jog',
|
|
|
|
'jit',
|
|
|
|
'lad',
|
|
|
|
'pig',
|
|
|
|
'got',
|
|
|
|
'tot',
|
|
|
|
'gak',
|
|
|
|
'sot',
|
|
|
|
'rin',
|
|
|
|
'lid',
|
|
|
|
'don',
|
|
|
|
'den',
|
|
|
|
'pod',
|
|
|
|
'rit',
|
|
|
|
'gat',
|
|
|
|
'ket',
|
|
|
|
'sab',
|
|
|
|
'rat',
|
|
|
|
'bub',
|
|
|
|
'dod',
|
|
|
|
'dep',
|
|
|
|
'dup',
|
|
|
|
'tod',
|
|
|
|
'lat',
|
|
|
|
'nub',
|
|
|
|
'lab',
|
|
|
|
'pan',
|
|
|
|
'rap',
|
|
|
|
'tib',
|
|
|
|
'tan',
|
|
|
|
'bed',
|
|
|
|
'seg',
|
|
|
|
'lib',
|
|
|
|
'kop',
|
|
|
|
'fog',
|
|
|
|
'tig',
|
|
|
|
'sob',
|
|
|
|
'pet',
|
|
|
|
'lop',
|
|
|
|
'bet',
|
|
|
|
'bog',
|
|
|
|
'nog',
|
|
|
|
'gun',
|
|
|
|
'lud',
|
|
|
|
'sit',
|
|
|
|
'dib',
|
|
|
|
'dap',
|
|
|
|
'ban',
|
|
|
|
'kob',
|
|
|
|
'nan',
|
|
|
|
'pat',
|
|
|
|
'pib',
|
|
|
|
'lip',
|
|
|
|
'fan',
|
|
|
|
'big',
|
|
|
|
'get',
|
|
|
|
'bob',
|
|
|
|
'rad',
|
|
|
|
'ran',
|
|
|
|
'san',
|
|
|
|
'rot',
|
|
|
|
'bad',
|
|
|
|
'nop',
|
|
|
|
'nid',
|
|
|
|
'jut',
|
|
|
|
'nod',
|
|
|
|
'bap',
|
|
|
|
'fad',
|
|
|
|
'ten',
|
|
|
|
'gid',
|
|
|
|
'dop',
|
|
|
|
'dit',
|
|
|
|
'fid',
|
|
|
|
'tap',
|
|
|
|
'bib',
|
|
|
|
'dog',
|
|
|
|
'lek',
|
|
|
|
'tog',
|
|
|
|
'deg',
|
|
|
|
'fob',
|
|
|
|
'deb',
|
|
|
|
'beg',
|
|
|
|
'kan',
|
|
|
|
'sug',
|
|
|
|
'tup',
|
|
|
|
'ton',
|
|
|
|
'gag',
|
|
|
|
'dot',
|
|
|
|
'lot',
|
|
|
|
'keg',
|
|
|
|
'pap',
|
|
|
|
'ren',
|
|
|
|
'fit',
|
|
|
|
'kip',
|
|
|
|
'tub',
|
|
|
|
'tin',
|
|
|
|
'pad',
|
|
|
|
'bip',
|
|
|
|
'pun',
|
|
|
|
'tug',
|
|
|
|
'nap',
|
|
|
|
'sag',
|
|
|
|
'dob',
|
|
|
|
'gig',
|
|
|
|
'sup',
|
|
|
|
'tag',
|
|
|
|
'fub',
|
|
|
|
'reg',
|
|
|
|
'top',
|
|
|
|
'jag',
|
|
|
|
'nib',
|
|
|
|
'sig',
|
|
|
|
'kit',
|
|
|
|
'dag',
|
|
|
|
'set',
|
|
|
|
'dud',
|
|
|
|
'bab',
|
|
|
|
'sud',
|
|
|
|
'sub',
|
|
|
|
'dub',
|
|
|
|
'nit',
|
|
|
|
'fed',
|
|
|
|
'nat',
|
|
|
|
'tad',
|
|
|
|
'dab',
|
|
|
|
'fen',
|
|
|
|
'nun',
|
|
|
|
'lug',
|
|
|
|
'kut',
|
|
|
|
'rep',
|
|
|
|
'fib',
|
|
|
|
'nab',
|
|
|
|
'nag',
|
|
|
|
'bok',
|
|
|
|
'gab',
|
|
|
|
'bot',
|
|
|
|
'bud',
|
|
|
|
'dad',
|
|
|
|
'sap',
|
|
|
|
'tat',
|
|
|
|
'did',
|
|
|
|
'gog',
|
|
|
|
'dat',
|
|
|
|
'rub',
|
|
|
|
'pud',
|
|
|
|
'bop',
|
|
|
|
'lig',
|
|
|
|
'dut',
|
|
|
|
'pep',
|
|
|
|
'fug',
|
|
|
|
'bod',
|
|
|
|
'sed',
|
|
|
|
'sen',
|
|
|
|
'teg',
|
|
|
|
'pit',
|
|
|
|
'fin',
|
|
|
|
'dun',
|
|
|
|
'rob',
|
|
|
|
'let',
|
|
|
|
'neb',
|
|
|
|
'tut',
|
|
|
|
'sop',
|
|
|
|
'gan',
|
|
|
|
'fig',
|
|
|
|
'tab'
|
|
|
|
];
|
|
|
|
|
2023-07-09 12:59:05 -04:00
|
|
|
Map<String, int> _phonoToByte = _buildPhonoToByte();
|
2023-07-09 10:55:26 -04:00
|
|
|
|
2023-07-09 12:59:05 -04:00
|
|
|
Map<String, int> _buildPhonoToByte() {
|
2023-07-26 14:20:29 -04:00
|
|
|
final phonoToByte = <String, int>{};
|
|
|
|
for (var b = 0; b < 256; b++) {
|
|
|
|
final ph = _byteToPhono[b];
|
2023-07-09 12:59:05 -04:00
|
|
|
phonoToByte[ph] = b;
|
|
|
|
}
|
|
|
|
return phonoToByte;
|
2023-07-09 10:55:26 -04:00
|
|
|
}
|
|
|
|
|
2023-07-09 12:59:05 -04:00
|
|
|
String prettyPhonoString(String s,
|
|
|
|
{int wordsPerLine = 5, int phonoPerWord = 2}) {
|
2023-07-26 17:42:11 -04:00
|
|
|
assert(wordsPerLine >= 1, 'Should not have zero or negative words per line');
|
|
|
|
assert(phonoPerWord >= 1, 'Should not have zero or negative phono per word');
|
2023-07-09 12:59:05 -04:00
|
|
|
final cs = canonicalPhonoString(s).toUpperCase();
|
2023-07-26 17:42:11 -04:00
|
|
|
final out = StringBuffer();
|
2023-07-26 14:20:29 -04:00
|
|
|
var words = 0;
|
|
|
|
var phonos = 0;
|
|
|
|
for (var i = 0; i < cs.length; i += 3) {
|
2023-07-09 12:59:05 -04:00
|
|
|
if (i != 0) {
|
|
|
|
phonos += 1;
|
|
|
|
if (phonos == phonoPerWord) {
|
|
|
|
phonos = 0;
|
|
|
|
words += 1;
|
|
|
|
if (words == wordsPerLine) {
|
|
|
|
words = 0;
|
2023-07-26 17:42:11 -04:00
|
|
|
out.write('\n');
|
2023-07-09 12:59:05 -04:00
|
|
|
} else {
|
2023-07-26 17:42:11 -04:00
|
|
|
out.write(' ');
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-07-26 17:42:11 -04:00
|
|
|
out.write(cs.substring(i, i + 3));
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
2023-07-26 17:42:11 -04:00
|
|
|
return out.toString();
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
2023-07-09 10:55:26 -04:00
|
|
|
|
2023-07-09 12:59:05 -04:00
|
|
|
String canonicalPhonoString(String s) {
|
2023-07-26 14:20:29 -04:00
|
|
|
final bytes = Uint8List.fromList(utf8.encode(s.toLowerCase()));
|
|
|
|
var cs = '';
|
|
|
|
for (var i = 0; i < bytes.length; i++) {
|
|
|
|
final ch = bytes[i];
|
2023-07-09 12:59:05 -04:00
|
|
|
if (ch >= $a && ch <= $z) {
|
|
|
|
cs += String.fromCharCode(ch);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cs.length % 3 != 0) {
|
|
|
|
throw const FormatException(
|
2023-07-26 14:20:29 -04:00
|
|
|
'phonobyte string length should be a multiple of 3');
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
2023-07-26 14:20:29 -04:00
|
|
|
for (var i = 0; i < cs.length; i += 3) {
|
|
|
|
final ph = cs.substring(i, i + 3);
|
2023-07-09 12:59:05 -04:00
|
|
|
if (!_phonoToByte.containsKey(ph)) {
|
2023-07-26 14:20:29 -04:00
|
|
|
throw const FormatException('phonobyte string contains invalid sequence');
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cs;
|
2023-07-09 10:55:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
Uint8List decodePhono(String s) {
|
2023-07-09 12:59:05 -04:00
|
|
|
final cs = canonicalPhonoString(s);
|
|
|
|
final out = Uint8List(cs.length ~/ 3);
|
2023-07-26 14:20:29 -04:00
|
|
|
for (var i = 0; i < cs.length; i += 3) {
|
|
|
|
final ph = cs.substring(i, i + 3);
|
|
|
|
final b = _phonoToByte[ph]!;
|
2023-07-09 12:59:05 -04:00
|
|
|
out[i] = b;
|
2023-07-09 10:55:26 -04:00
|
|
|
}
|
2023-07-09 12:59:05 -04:00
|
|
|
return out;
|
2023-07-09 10:55:26 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
String encodePhono(Uint8List b) {
|
2023-07-26 17:42:11 -04:00
|
|
|
final out = StringBuffer();
|
2023-07-26 14:20:29 -04:00
|
|
|
for (var i = 0; i < b.length; i++) {
|
2023-07-26 17:42:11 -04:00
|
|
|
out.write(_byteToPhono[b[i]]);
|
2023-07-09 12:59:05 -04:00
|
|
|
}
|
2023-07-26 17:42:11 -04:00
|
|
|
return out.toString();
|
2023-07-09 10:55:26 -04:00
|
|
|
}
|