1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
package io.ipfs.multibase;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
/*
* Copyright 2025 Michael Vorburger.ch
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* <a
* href="https://github.com/multiformats/multibase/blob/master/rfcs/Base256Emoji.md">Base256Emoji</a>
* is an encoding mapping each 0-255 byte value to (or from) a specific single Unicode Emoji
* character.
*
* @author <a href="https://www.vorburger.ch/">Michael Vorburger.ch</a>
*/
public class Base256Emoji {
// from https://github.com/multiformats/multibase/blob/master/rfcs/Base256Emoji.md
private static final String[] EMOJIS = {
"๐", "๐ช", "โ", "๐ฐ", "๐", "๐", "๐", "๐", "๐", "๐",
"๐", "๐", "๐", "๐", "๐", "๐", "๐", "โ", "๐ป", "๐ฅ",
"๐พ", "๐ฟ", "๐", "โค", "๐", "๐คฃ", "๐", "๐", "๐", "๐ญ",
"๐", "๐", "๐
", "๐", "๐", "๐ฅ", "๐ฅฐ", "๐", "๐", "๐",
"๐ข", "๐ค", "๐", "๐", "๐ช", "๐", "โบ", "๐", "๐ค", "๐",
"๐", "๐", "๐", "๐น", "๐คฆ", "๐", "๐", "โ", "โจ", "๐คท",
"๐ฑ", "๐", "๐ธ", "๐", "๐", "๐", "๐", "๐", "๐", "๐",
"๐", "๐คฉ", "๐", "๐", "๐ค", "๐", "๐ฏ", "๐", "๐", "๐ถ",
"๐", "๐คญ", "โฃ", "๐", "๐", "๐", "๐ช", "๐", "๐ฅ", "๐",
"๐", "๐ฉ", "๐ก", "๐คช", "๐", "๐ฅณ", "๐ฅ", "๐คค", "๐", "๐",
"๐ณ", "โ", "๐", "๐", "๐ด", "๐", "๐ฌ", "๐", "๐", "๐ท",
"๐ป", "๐", "โญ", "โ
", "๐ฅบ", "๐", "๐", "๐ค", "๐ฆ", "โ",
"๐ฃ", "๐", "๐", "โน", "๐", "๐", "๐ ", "โ", "๐", "๐บ",
"๐", "๐ป", "๐", "๐", "๐", "๐", "๐น", "๐ฃ", "๐ซ", "๐",
"๐", "๐ต", "๐ค", "๐", "๐ด", "๐ค", "๐ผ", "๐ซ", "โฝ", "๐ค",
"โ", "๐", "๐คซ", "๐", "๐ฎ", "๐", "๐ป", "๐", "๐ถ", "๐",
"๐ฒ", "๐ฟ", "๐งก", "๐", "โก", "๐", "๐", "โ", "โ", "๐",
"๐ฐ", "๐คจ", "๐ถ", "๐ค", "๐ถ", "๐ฐ", "๐", "๐ข", "๐ค", "๐",
"๐จ", "๐จ", "๐คฌ", "โ", "๐", "๐บ", "๐ค", "๐", "๐", "๐ฑ",
"๐", "๐ถ", "๐ฅด", "โถ", "โก", "โ", "๐", "๐ธ", "โฌ", "๐จ",
"๐", "๐ฆ", "๐ท", "๐บ", "โ ", "๐
", "๐", "๐ต", "๐", "๐คฒ",
"๐ค ", "๐คง", "๐", "๐ต", "๐
", "๐ง", "๐พ", "๐", "๐", "๐ค",
"๐", "๐คฏ", "๐ท", "โ", "๐ง", "๐ฏ", "๐", "๐", "๐ค", "๐",
"๐", "โ", "๐ด", "๐ฃ", "๐ธ", "๐", "๐", "๐ฅ", "๐คข", "๐
",
"๐ก", "๐ฉ", "๐", "๐ธ", "๐ป", "๐ค", "๐คฎ", "๐ผ", "๐ฅต", "๐ฉ",
"๐", "๐", "๐ผ", "๐", "๐ฃ", "๐ฅ"
};
// TODO Propose adding a Guava dependency to use ImmutableMap instead of this
private static final Map<String, Integer> EMOJI_TO_INDEX;
private static final int MAP_EXPECTED_SIZE = EMOJIS.length;
private static final float MAP_LOAD_FACTOR = 1.0f;
static {
if (EMOJIS.length != 256) {
throw new IllegalStateException("EMOJIS.length must be 256, but is " + EMOJIS.length);
}
Map<String, Integer> mutableMap = new HashMap<>(MAP_EXPECTED_SIZE, MAP_LOAD_FACTOR);
for (int i = 0; i < EMOJIS.length; i++) {
mutableMap.put(EMOJIS[i], i);
}
EMOJI_TO_INDEX = Collections.unmodifiableMap(mutableMap);
}
public static String encode(byte[] in) {
StringBuilder sb = new StringBuilder(in.length);
for (byte b : in) {
sb.append(EMOJIS[b & 0xFF]);
}
return sb.toString();
}
public static byte[] decode(String in) {
int length = in.codePointCount(0, in.length());
byte[] bytes = new byte[length];
for (int i = 0; i < in.codePointCount(0, in.length()); i++) {
int cp = in.codePointAt(in.offsetByCodePoints(0, i));
String emoji = new String(Character.toChars(cp));
Integer index = EMOJI_TO_INDEX.get(emoji);
if (index == null) {
throw new IllegalArgumentException("Unknown Base256Emoji character: " + emoji);
}
bytes[i] = (byte) (index & 0xFF);
}
return bytes;
}
}
|