|
| 1 | +/*! |
| 2 | + * DenCode |
| 3 | + * Copyright 2016 Mozq |
| 4 | + * |
| 5 | + * Licensed under the Apache License, Version 2.0 (the "License"); |
| 6 | + * you may not use this file except in compliance with the License. |
| 7 | + * You may obtain a copy of the License at |
| 8 | + * |
| 9 | + * http://www.apache.org/licenses/LICENSE-2.0 |
| 10 | + * |
| 11 | + * Unless required by applicable law or agreed to in writing, software |
| 12 | + * distributed under the License is distributed on an "AS IS" BASIS, |
| 13 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 14 | + * See the License for the specific language governing permissions and |
| 15 | + * limitations under the License. |
| 16 | + */ |
| 17 | +package com.dencode.logic.dencoder; |
| 18 | + |
| 19 | +import com.dencode.logic.dencoder.annotation.Dencoder; |
| 20 | +import com.dencode.logic.dencoder.annotation.DencoderFunction; |
| 21 | +import com.dencode.logic.model.DencodeCondition; |
| 22 | + |
| 23 | +@Dencoder(type="string", method="string.hieroglyphs", hasEncoder=true, hasDecoder=true) |
| 24 | +public class StringHieroglyphsDencoder { |
| 25 | + // See: [ISBN 978-0-7141-1976-2] Angela McDonald. Write Your Own Egyptian Hieroglyphs: Names, Greetings, Insults, Sayings. London, UK : The British Museum Press, 2007. |
| 26 | + // https://www.britishmuseumshoponline.org/write-your-own-egyptian-hieroglyphs.html |
| 27 | + // See: https://preview.memphis.edu/egypt/events/familyday2022/name_hieroglyphs.php |
| 28 | + // See: https://en.wikipedia.org/wiki/Transliteration_of_Ancient_Egyptian |
| 29 | + // See: https://en.wikipedia.org/wiki/List_of_Egyptian_hieroglyphs |
| 30 | + // See: https://www.britishmuseum.org/exhibitions/hieroglyphs-unlocking-ancient-egypt/egyptian-hieroglyphs-decipherment-timeline |
| 31 | + |
| 32 | + private StringHieroglyphsDencoder() { |
| 33 | + // NOP |
| 34 | + } |
| 35 | + |
| 36 | + @DencoderFunction |
| 37 | + public static String encStrHieroglyphs(DencodeCondition cond) { |
| 38 | + return encStrHieroglyphs(cond.value()); |
| 39 | + } |
| 40 | + |
| 41 | + @DencoderFunction |
| 42 | + public static String decStrHieroglyphs(DencodeCondition cond) { |
| 43 | + return decStrHieroglyphs(cond.value()); |
| 44 | + } |
| 45 | + |
| 46 | + private static String encStrHieroglyphs(String value) { |
| 47 | + if (value == null || value.isEmpty()) { |
| 48 | + return ""; |
| 49 | + } |
| 50 | + |
| 51 | + StringBuilder sb = null; |
| 52 | + |
| 53 | + int len = value.length(); |
| 54 | + for (int i = 0; i < len; i++) { |
| 55 | + char ch = value.charAt(i); |
| 56 | + |
| 57 | + String hieroglyph = switch (ch) { |
| 58 | + case 'A', 'a', 'A', 'a' -> "𓄿"; // 𓄿 (G1) |
| 59 | + case 'B', 'b', 'B', 'b' -> "𓃀"; // 𓃀 (D58) |
| 60 | + case 'C', 'c', 'C', 'c' -> "𓎡"; // 𓎡 (V31) |
| 61 | + case 'D', 'd', 'D', 'd' -> "𓂧"; // 𓂧 (D46) |
| 62 | + case 'E', 'e', 'E', 'e' -> "𓇋"; // 𓇋 (M17) |
| 63 | + case 'F', 'f', 'F', 'f' -> "𓆑"; // 𓆑 (I9) |
| 64 | + case 'G', 'g', 'G', 'g' -> "𓎼"; // 𓎼 (W11) |
| 65 | + case 'H', 'h', 'H', 'h' -> "𓉔"; // 𓉔 (O4) |
| 66 | + case 'I', 'i', 'I', 'i' -> "𓇋"; // 𓇋 (M17) |
| 67 | + case 'J', 'j', 'J', 'j' -> "𓆓"; // 𓆓 (I10) |
| 68 | + case 'K', 'k', 'K', 'k' -> "𓎡"; // 𓎡 (V31) |
| 69 | + case 'L', 'l', 'L', 'l' -> "𓃭"; // 𓃭 (E23) |
| 70 | + case 'M', 'm', 'M', 'm' -> "𓅓"; // 𓅓 (G17) |
| 71 | + case 'N', 'n', 'N', 'n' -> "𓈖"; // 𓈖 (N35) |
| 72 | + case 'O', 'o', 'O', 'o' -> "𓍯"; // 𓍯 (V4) |
| 73 | + case 'P', 'p', 'P', 'p' -> "𓊪"; // 𓊪 (Q3) |
| 74 | + case 'Q', 'q', 'Q', 'q' -> "𓈎"; // 𓈎 (N29) |
| 75 | + case 'R', 'r', 'R', 'r' -> "𓂋"; // 𓂋 (D21) |
| 76 | + case 'S', 's', 'S', 's' -> "𓋴"; // 𓋴 (S29) |
| 77 | + case 'T', 't', 'T', 't' -> "𓏏"; // 𓏏 (X1) |
| 78 | + case 'U', 'u', 'U', 'u' -> "𓏲"; // 𓏲 (Z7) |
| 79 | + case 'V', 'v', 'V', 'v' -> "𓆑"; // 𓆑 (I9) |
| 80 | + case 'W', 'w', 'W', 'w' -> "𓅱"; // 𓅱 (G43) |
| 81 | + case 'X', 'x', 'X', 'x' -> "𓎡𓋴"; // 𓎡𓋴 (V31+S29) |
| 82 | + case 'Y', 'y', 'Y', 'y' -> "𓇌"; // 𓇌 (M17A) |
| 83 | + case 'Z', 'z', 'Z', 'z' -> "𓊃"; // 𓊃 (O34) |
| 84 | + default -> null; |
| 85 | + }; |
| 86 | + |
| 87 | + if (hieroglyph != null) { |
| 88 | + if (sb == null) { |
| 89 | + sb = new StringBuilder(value.length() * 2); |
| 90 | + sb.append(value, 0, i); |
| 91 | + } |
| 92 | + sb.append(hieroglyph); |
| 93 | + } else { |
| 94 | + if (sb != null) { |
| 95 | + sb.append(ch); |
| 96 | + } |
| 97 | + } |
| 98 | + } |
| 99 | + |
| 100 | + return (sb != null) ? sb.toString() : value; |
| 101 | + } |
| 102 | + |
| 103 | + private static String decStrHieroglyphs(String value) { |
| 104 | + if (value == null || value.isEmpty()) { |
| 105 | + return ""; |
| 106 | + } |
| 107 | + |
| 108 | + int len = value.length(); |
| 109 | + StringBuilder sb = null; |
| 110 | + |
| 111 | + for (int i = 0; i < len; ) { |
| 112 | + int lastIdx = i; |
| 113 | + int cp = value.codePointAt(i); |
| 114 | + cp = normalizeHieroglyph(cp); |
| 115 | + i += Character.charCount(cp); |
| 116 | + |
| 117 | + int dcp = switch (cp) { |
| 118 | + case 0x1313F, 0x1309D -> 'A'; // 𓄿 (G1), 𓂝 (D36) |
| 119 | + case 0x130C0 -> 'B'; // 𓃀 (D58) |
| 120 | + case 0x130A7, 0x130BD -> 'D'; // 𓂧 (D46), 𓂽 (D55) |
| 121 | + case 0x13191 -> 'F'; // 𓆑 (I9) |
| 122 | + case 0x133BC, 0x133BD, 0x1317C -> 'G'; // 𓎼 (W11), 𓎽 (W12), 𓅼 (G52) |
| 123 | + case 0x13254, 0x1339B -> 'H'; // 𓉔 (O4), 𓎛 (V28) |
| 124 | + case 0x131CB -> 'I'; // 𓇋 (M17) |
| 125 | + case 0x13193 -> 'J'; // 𓆓 (I10) |
| 126 | + case 0x133A1 -> { |
| 127 | + int ncp = (i < len) ? value.codePointAt(i) : -1; |
| 128 | + ncp = normalizeHieroglyph(ncp); |
| 129 | + if (ncp == 0x132F4 || ncp == 0x13283) { |
| 130 | + i += Character.charCount(ncp); |
| 131 | + yield 'X'; // 𓎡𓋴 (V31+S29), 𓎡𓊃 (V31+O34) |
| 132 | + } else { |
| 133 | + yield 'K'; // 𓎡 (V31) |
| 134 | + } |
| 135 | + } |
| 136 | + case 0x133A2 -> 0x133A1; // K : 𓎢 (V31A) -> 𓎡(V31) |
| 137 | + case 0x130ED -> 'L'; // 𓃭 (E23) |
| 138 | + case 0x13153, 0x1341D -> 'M'; // 𓅓 (G17), 𓐝 (Aa15) |
| 139 | + case 0x13216, 0x132D4 -> 'N'; // 𓈖 (N35), 𓋔 (S3) |
| 140 | + case 0x1336F -> 'O'; // 𓍯 (V4) |
| 141 | + case 0x132AA -> 'P'; // 𓊪 (Q3) |
| 142 | + case 0x1320E -> { |
| 143 | + int ncp = (i < len) ? value.codePointAt(i) : -1; |
| 144 | + ncp = normalizeHieroglyph(ncp); |
| 145 | + if (ncp == 0x13283) { |
| 146 | + i += Character.charCount(ncp); |
| 147 | + yield 'X'; // 𓈎𓊃 (N29+O34) |
| 148 | + } else { |
| 149 | + yield 'Q'; // 𓈎 (N29) |
| 150 | + } |
| 151 | + } |
| 152 | + case 0x1308B -> 'R'; // 𓂋 (D21) |
| 153 | + case 0x132F4, 0x13219 -> 'S'; // 𓋴 (S29), 𓈙 (N37) |
| 154 | + case 0x133CF, 0x1337F -> 'T'; // 𓏏 (X1), 𓍿 (V13) |
| 155 | + case 0x133F2 -> 'U'; // 𓏲 (Z7) |
| 156 | + case 0x13171 -> 'W'; // 𓅱 (G43) |
| 157 | + case 0x1340D, 0x13121 -> 'X'; // 𓐍 (Aa1), 𓄡 (F32) |
| 158 | + case 0x131CC, 0x133ED -> 'Y'; // 𓇌 (M17A), 𓏭 (Z4) |
| 159 | + case 0x13283 -> 'Z'; // 𓊃 (O34) |
| 160 | + default -> cp; |
| 161 | + }; |
| 162 | + |
| 163 | + if (dcp != cp && sb == null) { |
| 164 | + sb = new StringBuilder(len); |
| 165 | + sb.append(value, 0, lastIdx); |
| 166 | + } |
| 167 | + if (sb != null) { |
| 168 | + sb.appendCodePoint(dcp); |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return (sb != null) ? sb.toString() : value; |
| 173 | + } |
| 174 | + |
| 175 | + private static final int normalizeHieroglyph(int cp) { |
| 176 | + return switch (cp) { |
| 177 | + // Convert variant symbols to standard ones |
| 178 | + case 0x133A2 -> 0x133A1; // C, K : 𓎢 (V31A) -> 𓎡 (V31) |
| 179 | + case 0x1321A, 0x1321B, 0x1321C -> 0x13219; // S : 𓈚 (N37A), 𓈛 (N38), 𓈜 (N39) -> 𓈙 (N37) |
| 180 | + |
| 181 | + // Convert incorrect symbols to correct ones |
| 182 | + case 0x130BE -> 0x130C0; // B : 𓂾 (D56) -> 𓃀 (D58) |
| 183 | + case 0x130EC -> 0x130ED; // L : 𓃬 (E22) -> 𓃭 (E23) |
| 184 | + case 0x133E4 -> 0x132AA; // P : 𓏤 (Z1) -> 𓊪 (Q3) |
| 185 | + case 0x133D8 -> 0x1320E; // Q : 𓏘 (X7) -> 𓈎 (N29) |
| 186 | + case 0x13362 -> 0x133F2; // U : 𓍢 (V1) -> 𓏲 (Z7) |
| 187 | + case 0x1331F -> 0x1340D; // X : 𓌟 (T19) -> 𓐍 (Aa1) |
| 188 | + |
| 189 | + default -> cp; |
| 190 | + }; |
| 191 | + } |
| 192 | +} |
0 commit comments