diff --git a/nx01-warp-manifestor/src/main/java/love/distributedrebirth/nx01/warp/manifestor/manifest/WarpManifestX18Import.java b/nx01-warp-manifestor/src/main/java/love/distributedrebirth/nx01/warp/manifestor/manifest/WarpManifestX18Import.java index 6a31452..2021d87 100644 --- a/nx01-warp-manifestor/src/main/java/love/distributedrebirth/nx01/warp/manifestor/manifest/WarpManifestX18Import.java +++ b/nx01-warp-manifestor/src/main/java/love/distributedrebirth/nx01/warp/manifestor/manifest/WarpManifestX18Import.java @@ -27,11 +27,8 @@ package love.distributedrebirth.nx01.warp.manifestor.manifest; -import java.util.List; - -import org.x4o.o2o.fc18.FCDotCDC1604DashP6; +import org.x4o.o2o.fc18.FourCornerUnicodeImport; import org.x4o.o2o.octal.PrimordialOctalOrangeJuiceCord; -import org.x4o.o2o.octal.PrimordialOctalOrangeString; /// Warp manifest 18 bit model importer from 8 bit model /// @@ -43,38 +40,31 @@ public final class WarpManifestX18Import { } static public WarpManifestX18 fromX8(WarpManifestX8 manifest) { + WarpManifestX18Section sectionX18 = null; + WarpManifestX18HeaderField fieldX18 = null; WarpManifestX18 result = new WarpManifestX18(); - for (WarpManifestX8HeaderField attr : manifest.getAttributes()) { - PrimordialOctalOrangeJuiceCord name = convertX8(attr.getName()); - PrimordialOctalOrangeJuiceCord body = convertX8(attr.getBody()); - WarpManifestX18HeaderField field = result.makeAttribute(name, body); - convertRemarks(field, attr.getRemarks()); + for (WarpManifestX8HeaderField attrX8 : manifest.getAttributes()) { + fieldX18 = result.makeAttribute(toX8(attrX8.getName()), toX8(attrX8.getBody())); + for (String remark : attrX8.getRemarks()) { + fieldX18.withRemark(toX8(remark)); + } } for (WarpManifestX8Section sectionX8 : manifest.getSections()) { - PrimordialOctalOrangeJuiceCord sectionName = convertX8(sectionX8.getName()); - WarpManifestX18Section sectionX18 = result.makeSection(sectionName); + sectionX18 = result.makeSection(toX8(sectionX8.getName())); for (String remark : sectionX8.getRemarks()) { - sectionX18.withRemark(convertX8(remark)); + sectionX18.withRemark(toX8(remark)); } - for (WarpManifestX8HeaderField attr : sectionX8.getAttributes()) { - PrimordialOctalOrangeJuiceCord name = convertX8(attr.getName()); - PrimordialOctalOrangeJuiceCord body = convertX8(attr.getBody()); - WarpManifestX18HeaderField field = sectionX18.makeAttribute(name, body); - convertRemarks(field, attr.getRemarks()); + for (WarpManifestX8HeaderField attrX8 : sectionX8.getAttributes()) { + fieldX18 = sectionX18.makeAttribute(toX8(attrX8.getName()), toX8(attrX8.getBody())); + for (String remark : attrX8.getRemarks()) { + fieldX18.withRemark(toX8(remark)); + } } } return result; } - static private void convertRemarks(WarpManifestX18HeaderField field, List remarks) { - for (String remark : remarks) { - field.withRemark(convertX8(remark)); - } - } - - static private PrimordialOctalOrangeJuiceCord convertX8(String value) { - List fc18 = FCDotCDC1604DashP6.convertFromUnicode(value); - List fc18Num = fc18.stream().map(v -> v.ordinal()).toList(); - return PrimordialOctalOrangeString.valueOfSmurfs(fc18Num); + static private PrimordialOctalOrangeJuiceCord toX8(String value) { + return FourCornerUnicodeImport.lossy().convertToJuice(value); } } diff --git a/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6.java b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6.java index 305a2cf..813c5a5 100644 --- a/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6.java +++ b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6.java @@ -22,11 +22,6 @@ */ package org.x4o.o2o.fc18; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; -import java.util.PrimitiveIterator; - /// /// "FC.CDC1604-P6" has 27 pie slice number systems "Packed" for MATH and BASIC letters in a "Six" bit encoding. /// @@ -97,48 +92,41 @@ public enum FCDotCDC1604DashP6 { BAR_V_RIGHT('/'), _AT('@'), /// The tone letter 'A' is "one" and is equal to 'a', if your computer is expensive and has a lower-case char ROM, than this is 'a' except after __GLUE marker. - NX01_A('A', "Æ æ Å å Ǻ ǻ Ḁ ḁ ẚ Ă ă Ặ ặ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ȃ ȃ Â â Ậ ậ Ấ ấ Ầ ầ Ẫ ẫ Ẩ ẩ Ả ả Ǎ ǎ Ⱥ ⱥ Ȧ ȧ Ǡ ǡ Ạ ạ Ä ä Ǟ ǟ À à Ȁ ȁ Á á Ā ā Ā̀ ā̀ Ã ã Ą ą Ą́ ą́ Ą̃ ą̃ A̲ a̲ ᶏ"), - NX02_B('B', "Ƀ ƀ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ɓ ɓ ᵬ ᶀ"), - NX03_C('C', "Ć ć Ĉ ĉ Č č Ċ ċ Ḉ ḉ Ƈ ƈ C̈ c̈ Ȼ ȼ Ç ç Ꞔ ꞔ Ꞓ ꞓ"), - NX04_D('D', "Đ đ Ꟈ ꟈ Ɗ ɗ Ḋ ḋ Ḍ ḍ Ḑ ḑ Ḓ ḓ Ď ď Ḏ ḏ"), - NX05_E('E', "Ĕ ĕ Ḝ ḝ Ȇ ȇ Ê ê Ê̄ ê̄ Ê̌ ê̌ Ề ề Ế ế Ể ể Ễ ễ Ệ ệ Ẻ ẻ Ḙ ḙ Ě ě Ɇ ɇ Ė ė Ė́ ė́ Ė̃ ė̃ Ẹ ẹ Ë ë È è È̩ è̩ Ȅ ȅ É é É̩ Ē ē Ḕ ḕ Ḗ ḗ Ẽ ẽ Ḛ ḛ Ę ę Ę́ ę́ Ę̃ ę̃ Ȩ ȩ E̩ e̩ ᶒ"), - NX06_F('F', "Ƒ ƒ Ḟ ḟ ᵮ ᶂ Ꞙ ꞙ"), - NX07_G('G', "Ǵ ǵ Ǥ ǥ Ĝ ĝ Ǧ ǧ Ğ ğ Ģ ģ Ɠ ɠ Ġ ġ Ḡ ḡ Ꞡ ꞡ ᶃ"), - NX08_H('H', "Ĥ ĥ Ȟ ȟ Ħ ħ Ḩ ḩ Ⱨ ⱨ ẖ ẖ Ḥ ḥ Ḣ ḣ Ḧ ḧ Ḫ ḫ ꞕ Ꜧ ꜧ"), - NX09_I('I', "Ị ị Ĭ ĭ Î î Ǐ ǐ Ɨ ɨ Ï ï Ḯ ḯ Í í Ì ì Ȉ ȉ Į į Į́ Į̃ Ī ī Ī̀ ī̀ ᶖ Ỉ ỉ Ȋ ȋ Ĩ ĩ Ḭ ḭ ᶤ"), - NX10_J('J', "J́ j́ Ĵ ĵ J̌ ǰ Ɉ ɉ J̃ j̇̃"), - NX11_K('K', "Ƙ ƙ Ꝁ ꝁ Ḱ ḱ Ǩ ǩ Ḳ ḳ Ķ ķ ᶄ Ⱪ ⱪ Ḵ ḵ"), - NX12_L('L', "Ĺ ĺ Ł ł Ľ ľ Ḹ ḹ L̃ l̃ Ļ ļ Ŀ ŀ Ḷ ḷ Ḻ ḻ Ḽ ḽ Ƚ ƚ Ⱡ ⱡ"), - NX13_M('M', "Ḿ ḿ Ṁ ṁ Ṃ ṃ M̃ m̃ ᵯ"), - NX14_N('N', "Ń ń Ñ ñ Ň ň Ǹ ǹ Ṅ ṅ Ṇ ṇ Ņ ņ Ṉ ṉ Ṋ ṋ Ꞥ ꞥ ᵰ ᶇ"), - NX15_O('O', "Ø ø Ǿ ǿ Ö ö Ȫ ȫ Ó ó Ò ò Ô ô Ố ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ǒ ǒ Ő ő Ŏ ŏ Ȏ ȏ Ȯ ȯ Ȱ ȱ Ọ ọ Ɵ ɵ ᶱ Ơ ơ Ớ ớ Ờ ờ Ỡ ỡ Ợ ợ Ở ở Ỏ ỏ Ō ō Ṓ ṓ Ṑ ṑ Õ õ Ȭ ȭ Ṍ ṍ Ṏ ṏ Ǫ ǫ Ȍ ȍ O̩ o̩ Ó̩ ó̩ Ò̩ ò̩ Ǭ ǭ O͍ o͍"), - NX16_P('P', "Ṕ ṕ Ṗ ṗ Ᵽ ᵽ Ƥ ƥ ᵱ ᶈ"), - NX17_Q('Q', "ʠ Ɋ ɋ q̃"), - NX18_R('R', "Ŕ ŕ Ɍ ɍ Ř ř Ŗ ŗ Ṙ ṙ Ȑ ȑ Ȓ ȓ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ꞧ ꞧ Ɽ ɽ R̃ r̃ ᵲ ꭨ ᵳ ᶉ"), - NX19_S('S', "Ś ś Ṡ ṡ ẛ Ṩ ṩ Ṥ ṥ Ṣ ṣ S̩ s̩ Ꞩ ꞩ Ꟊ ꟊ Ꟍ ꟍ Ŝ ŝ Ṧ ṧ Š š Ş ş Ș ș S̈ s̈ ᶊ Ȿ ȿ ᵴ ᶳ"), - NX20_T('T', "Ť ť Ṫ ṫ ẗ Ţ ţ Ṭ ṭ Ʈ ʈ Ț ț ƫ Ṱ ṱ Ṯ ṯ Ŧ ŧ Ⱦ ⱦ Ƭ ƭ ᵵ ᶵ"), - NX21_U('U', "Ŭ ŭ Ʉ ʉ ᵾ ᶶ Ꞹ ꞹ Ụ ụ Ü ü Ǜ ǜ Ǘ ǘ Ǚ ǚ Ǖ ǖ Ṳ ṳ Ú ú Ù ù Û û Ṷ ṷ Ǔ ǔ Ȗ ȗ Ű ű Ŭ ŭ Ư ư Ứ ứ Ừ ừ Ử ử Ự ự Ữ Ữ Ủ ủ Ū ū Ū̀ ū̀ Ū́ ū́ Ṻ ṻ Ū̃ ū̃ Ũ ũ Ṹ ṹ Ṵ ṵ ᶙ Ų ų Ų́ ų́ Ų̃ ų̃ Ȕ ȕ Ů ů"), - NX22_V('V', "Ṽ ṽ Ṿ ṿ Ʋ ʋ ᶌ"), - NX23_W('W', "Ẃ ẃ Ẁ ẁ Ŵ ŵ Ẅ ẅ Ẇ ẇ Ẉ ẉ ẘ"), - NX24_X('X', "Ẍ ẍ Ẋ ẋ X̂ x̂ ᶍ"), - NX25_Y('Y', "Ý ý Ỳ ỳ Ŷ ŷ Ÿ ÿ Ỹ ỹ Ẏ ẏ Ỵ ỵ ẙ Ỷ ỷ Ȳ ȳ Ɏ ɏ Ƴ ƴ"), - NX26_Z('Z', "Ź ź Ẑ ẑ Ž ž Ż ż Ẓ ẓ Ẕ ẕ Ƶ ƶ ᵶ Ᶎ ᶎ Ⱬ ⱬ"), + NX01_A('A'), + NX02_B('B'), + NX03_C('C'), + NX04_D('D'), + NX05_E('E'), + NX06_F('F'), + NX07_G('G'), + NX08_H('H'), + NX09_I('I'), + NX10_J('J'), + NX11_K('K'), + NX12_L('L'), + NX13_M('M'), + NX14_N('N'), + NX15_O('O'), + NX16_P('P'), + NX17_Q('Q'), + NX18_R('R'), + NX19_S('S'), + NX20_T('T'), + NX21_U('U'), + NX22_V('V'), + NX23_W('W'), + NX24_X('X'), + NX25_Y('Y'), + NX26_Z('Z'), /// The 27th letter is at the end of the old english alphabet. NX27_AMPERSAND('&'), ; - private final byte codePoint; - private final byte codePointLower; - private final String aliases; + static final private FCDotCDC1604DashP6[] P6_ALL = values(); + private final byte asciiByte; private FCDotCDC1604DashP6(char codePoint) { - this(codePoint, null); - } - - private FCDotCDC1604DashP6(char codePoint, String aliases) { - this.codePoint = (byte) codePoint; - this.codePointLower = (byte) Character.toLowerCase(codePoint); - this.aliases = aliases; + this.asciiByte = (byte) codePoint; } public byte cdcByte() { @@ -146,140 +134,14 @@ public enum FCDotCDC1604DashP6 { } public byte asciiByte() { - return codePoint; + return asciiByte; } - static public List convertFromUnicode(String text) { - return convertFromUnicode(text, false); + static public int length() { + return P6_ALL.length; } - static public List convertFromUnicode(String text, boolean strict) { - String textSingleNewLines = text.replaceAll("\r\n", "\n"); - PrimitiveIterator.OfInt i = textSingleNewLines.codePoints().iterator(); - List result = new ArrayList<>(text.length()); - FCDotCDC1604DashP6[] cdcChars = values(); - FCDotCDC1604DashP6 cdcNumberTerminator = null; - while (i.hasNext()) { - int codePoint = i.next(); - boolean found = false; - if ('\r' == codePoint) { - result.add(FCDotCDC1604DashP6.__LINE); - continue; - } - for (FCDotCDC1604DashP6 v : cdcChars) { - if (v.codePoint == codePoint) { - result.add(v); - found = true; - cdcNumberTerminator = null; - break; - } - if ('0' == codePoint) { - if (!FCDotCDC1604DashP6.NX01_A.equals(cdcNumberTerminator)) { - result.add(FCDotCDC1604DashP6.__PIE); - result.add(FCDotCDC1604DashP6.NX01_A); - cdcNumberTerminator = FCDotCDC1604DashP6.NX01_A; - } - result.add(FCDotCDC1604DashP6.NX01_A); - found = true; - break; - } - if (codePoint >= '1' && codePoint <= '9') { - if (!FCDotCDC1604DashP6.NX09_I.equals(cdcNumberTerminator)) { - result.add(FCDotCDC1604DashP6.__PIE); - result.add(FCDotCDC1604DashP6.NX09_I); - cdcNumberTerminator = FCDotCDC1604DashP6.NX09_I; - } - int cdcNumberOff = codePoint - '1'; // 0 = 1 - int cdcNumber = FCDotCDC1604DashP6.NX01_A.ordinal() + cdcNumberOff; - result.add(FCDotCDC1604DashP6.values()[cdcNumber]); - found = true; - break; - } - } - if (!found && !strict) { - String codePointStr = Character.toString(codePoint); - for (FCDotCDC1604DashP6 v : cdcChars) { - if (v.codePointLower == codePoint) { - result.add(v); - found = true; - cdcNumberTerminator = null; - break; - } - if (v.aliases == null) { - continue; - } - if (v.aliases.contains(codePointStr)) { - result.add(v); - found = true; - cdcNumberTerminator = null; - break; - } - } - } - if (!found) { - throw new IllegalArgumentException("Unsupported char: '" + ((char)codePoint) + "' 0x" + Integer.toHexString(codePoint)); - } - } - return result; - } - - static public String convertToUnicode(List cdcChars) { - StringBuilder buf = new StringBuilder(); - Iterator cdc = cdcChars.iterator(); - FCDotCDC1604DashP6 numberMode = null; - while (cdc.hasNext()) { - FCDotCDC1604DashP6 cdcPoint = cdc.next(); - if (numberMode != null && (cdcPoint.ordinal() > numberMode.ordinal())) { - numberMode = null; // out of range - } - if (numberMode != null && (cdcPoint.ordinal() < FCDotCDC1604DashP6.NX01_A.ordinal())) { - numberMode = null; // below index 1 is end number mode - } - if (FCDotCDC1604DashP6.__PIE.equals(cdcPoint)) { - if (!cdc.hasNext()) { - break; - } - numberMode = cdc.next(); - if (numberMode.ordinal() < FCDotCDC1604DashP6.NX01_A.ordinal()) { - cdcPoint = numberMode; // print char - numberMode = null; // illegal number mode - } else { - continue; - } - } - if (FCDotCDC1604DashP6.__GLUE.equals(cdcPoint)) { - continue; - } - if (numberMode == null) { - buf.appendCodePoint(cdcPoint.asciiByte()); - } else { - int terminatorNum = numberMode.ordinal() - FCDotCDC1604DashP6.NX01_A.ordinal() + 1; - int valueNumber = cdcPoint.ordinal() - FCDotCDC1604DashP6.NX01_A.ordinal(); - appendTerminatorNumber(buf, terminatorNum, valueNumber); - } - } - return buf.toString(); - } - - static private void appendTerminatorNumber(StringBuilder buf, int terminator, int value) { - switch (terminator) { - case 1: - buf.appendCodePoint('0'); // T001 is zero for all 27 gematria number systems. - return; - case 2: - if (value == 0) { - buf.append("true"); // FIXME: T002ᖟGunPunchedHoles would be better, as it supports two-way conversion - } else { - buf.append("false"); - } - return; - //case 3: - // return; // TODO: after nether DB, generate add all terminator up to 27 from "number system" gun bullets. - case 9: - buf.appendCodePoint(('1' + value)); // 0 = 1 - return; // NOTE: Latin decimals are not decimals as zero is not a part of the pie. - default: - throw new IllegalArgumentException("Unsupported terminator index: " + terminator); - } + static public FCDotCDC1604DashP6 indexOf(int idx) { + return P6_ALL[idx]; } } diff --git a/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeDisplay.java b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeDisplay.java new file mode 100644 index 0000000..c3efc42 --- /dev/null +++ b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeDisplay.java @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2004-2014, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.x4o.o2o.fc18; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.function.Consumer; + +import org.x4o.o2o.octal.PrimordialOctalOrangeJuiceCord; + +/// Renders unicode from four corner 18 bit text. +/// +/// @author Willem Cazander +/// @version 1.0 Dec 28, 2024 +public class FourCornerUnicodeDisplay { + + static private final FourCornerUnicodeDisplay DISPLAY_6BIT = new FourCornerUnicodeDisplay(false, null); + static private final FourCornerUnicodeDisplay DISPLAY_8BIT = new FourCornerUnicodeDisplay(true, null); + static private final FourCornerUnicodeDisplay DISPLAY_ESKIMO = new FourCornerUnicodeDisplay(true, "ᐧ"); + private boolean renderCasing = false; + private String renderSeperator = null; + + private FourCornerUnicodeDisplay(boolean renderCasing, String renderSeperator) { + this.renderCasing = renderCasing; + this.renderSeperator = renderSeperator; + } + + static FourCornerUnicodeDisplay simple() { + return DISPLAY_6BIT; + } + + static FourCornerUnicodeDisplay mixed() { + return DISPLAY_8BIT; + } + + static FourCornerUnicodeDisplay mixedᐧEskimo() { + return DISPLAY_ESKIMO; + } + + + private String buildString(Consumer appender) { + StringBuilder buf = new StringBuilder(); + appender.accept(buf); + return buf.toString(); + } + + public String renderFromP6(List chars) { + return buildString(v -> renderFromP6(chars, v)); + } + + public void renderFromP6(List chars, StringBuilder buf) { + renderFromInt18(chars.stream().map(v -> v.ordinal()).toList(), buf); + } + + public String renderFromJuice(PrimordialOctalOrangeJuiceCord chars) { + return buildString(v -> renderFromJuice(chars, v)); + } + + public void renderFromJuice(PrimordialOctalOrangeJuiceCord chars, StringBuilder buf) { + List int18 = new ArrayList<>(); + chars.juiceForEach(v -> int18.add(v.baitOctalNumber())); + renderFromInt18(int18, buf); + } + + public String renderFromInt18(List chars) { + return buildString(v -> renderFromInt18(chars, v)); + } + + public void renderFromInt18(List chars, StringBuilder buf) { + Iterator cdc = chars.iterator(); + Integer numberMode = null; + boolean prevLetter = false; + boolean toUpper = false; + while (cdc.hasNext()) { + Integer cdcPoint = cdc.next(); + if (numberMode != null && (cdcPoint > numberMode)) { + numberMode = null; // out of range + } + if (numberMode != null && (cdcPoint < FCDotCDC1604DashP6.NX01_A.ordinal())) { + numberMode = null; // below index 1 is end number mode + } + if (FCDotCDC1604DashP6.__PIE.ordinal() == cdcPoint) { + if (!cdc.hasNext()) { + break; + } + numberMode = cdc.next(); + if (numberMode < FCDotCDC1604DashP6.NX01_A.ordinal()) { + cdcPoint = numberMode; // print char + numberMode = null; // illegal number mode + } else { + continue; + } + } + if (FCDotCDC1604DashP6.__GLUE.ordinal() == cdcPoint) { + if (renderCasing) { + toUpper = true; + } + if (renderSeperator != null && prevLetter) { + buf.append(renderSeperator); + } + continue; + } + if (numberMode == null) { + prevLetter = cdcPoint >= FCDotCDC1604DashP6.NX01_A.ordinal(); + if (cdcPoint < FCDotCDC1604DashP6.length()) { + byte ch = FCDotCDC1604DashP6.indexOf(cdcPoint).asciiByte(); + if (renderCasing) { + if (toUpper) { + toUpper = false; + buf.appendCodePoint(ch); // revered casing as default is upper + } else { + buf.appendCodePoint(Character.toLowerCase(ch)); + } + } else { + buf.appendCodePoint(ch); + } + + } else { + // FIXME: print hex of 4C word until later print correct words for locate from nether db. + buf.append("&#x"); + buf.append(Integer.toHexString(cdcPoint).toUpperCase()); + buf.append(";"); + } + } else { + int terminatorNum = numberMode - FCDotCDC1604DashP6.NX01_A.ordinal() + 1; + int valueNumber = cdcPoint - FCDotCDC1604DashP6.NX01_A.ordinal(); + appendTerminatorNumber(buf, terminatorNum, valueNumber); + } + } + } + + static private void appendTerminatorNumber(StringBuilder buf, int terminator, int value) { + switch (terminator) { + case 1: + buf.appendCodePoint('0'); // T001 is zero for all 27 gematria number systems. + return; + case 2: + if (value == 0) { + buf.append("true"); // FIXME: T002ᖟGunPunchedHoles would be better, as it supports two-way conversion + } else { + buf.append("false"); + } + return; + //case 3: + // return; // TODO: after nether DB, generate add all terminator up to 27 from "number system" gun bullets. + case 9: + buf.appendCodePoint(('1' + value)); // 0 = 1 + return; // NOTE: Latin decimals are not decimals as zero is not a part of the pie. + default: + throw new IllegalArgumentException("Unsupported terminator index: " + terminator); + } + } +} diff --git a/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeImport.java b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeImport.java new file mode 100644 index 0000000..aed02a1 --- /dev/null +++ b/nx01-x4o-o2o/src/main/java/org/x4o/o2o/fc18/FourCornerUnicodeImport.java @@ -0,0 +1,224 @@ +/* + * Copyright (c) 2004-2014, Willem Cazander + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided + * that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and + * the following disclaimer in the documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.x4o.o2o.fc18; + +import java.util.ArrayList; +import java.util.List; +import java.util.PrimitiveIterator; + +import org.x4o.o2o.octal.PrimordialOctalOrangeJuiceCord; +import org.x4o.o2o.octal.PrimordialOctalOrangeString; + +/// +/// Imports unicode as four corner BASIC text from the "FC.CDC1604-P6" code page. +/// +/// @author Willem Cazander +/// @version 1.0 Dec 28, 2024 +/// +public class FourCornerUnicodeImport { + + static private final FourCornerUnicodeImport IMPORT_STRICT = new FourCornerUnicodeImport(false, false); + static private final FourCornerUnicodeImport IMPORT_LOSSY = new FourCornerUnicodeImport(true, true); + private boolean convertLowerCase = false; + private boolean convertDiacritics = false; + //private boolean convertWordGlue = false; // FIXME: detect changing case like: " [_GLUE]Abb[_GLUE]A" + + public FourCornerUnicodeImport(boolean convertLowerCase, boolean convertDiacritics) { + this.convertLowerCase = convertLowerCase; + this.convertDiacritics = convertDiacritics; + } + + static public FourCornerUnicodeImport strict() { + return IMPORT_STRICT; + } + + static public FourCornerUnicodeImport lossy() { + return IMPORT_LOSSY; + } + + public PrimordialOctalOrangeJuiceCord convertToJuice(String text) { + return PrimordialOctalOrangeString.valueOfSmurfs(convertToInt18(text)); + } + + public List convertToInt18(String text) { + return convertToP6(text).stream().map(v -> v.ordinal()).toList(); + } + + public List convertToP6(String text) { + String textSingleNewLines = text.replaceAll("\r\n", "\n"); // FIXME: regex only allowed in test scope classpath + PrimitiveIterator.OfInt i = textSingleNewLines.codePoints().iterator(); + List result = new ArrayList<>(text.length()); + FCDotCDC1604DashP6[] cdcChars = FCDotCDC1604DashP6.values(); + FCDotCDC1604DashP6 cdcNumberTerminator = null; + while (i.hasNext()) { + int codePoint = i.next(); + boolean found = false; + if ('\r' == codePoint) { + result.add(FCDotCDC1604DashP6.__LINE); + continue; + } + for (FCDotCDC1604DashP6 v : cdcChars) { + if (v.asciiByte() == codePoint) { + result.add(v); + found = true; + cdcNumberTerminator = null; + break; + } + if ('0' == codePoint) { + if (!FCDotCDC1604DashP6.NX01_A.equals(cdcNumberTerminator)) { + result.add(FCDotCDC1604DashP6.__PIE); + result.add(FCDotCDC1604DashP6.NX01_A); + cdcNumberTerminator = FCDotCDC1604DashP6.NX01_A; + } + result.add(FCDotCDC1604DashP6.NX01_A); + found = true; + break; + } + if (codePoint >= '1' && codePoint <= '9') { + if (!FCDotCDC1604DashP6.NX09_I.equals(cdcNumberTerminator)) { + result.add(FCDotCDC1604DashP6.__PIE); + result.add(FCDotCDC1604DashP6.NX09_I); + cdcNumberTerminator = FCDotCDC1604DashP6.NX09_I; + } + int cdcNumberOff = codePoint - '1'; // 0 = 1 + int cdcNumber = FCDotCDC1604DashP6.NX01_A.ordinal() + cdcNumberOff; + result.add(FCDotCDC1604DashP6.values()[cdcNumber]); + found = true; + break; + } + } + if (!found) { + String codePointStr = Character.toString(codePoint); + for (FCDotCDC1604DashP6 v : cdcChars) { + if (convertLowerCase) { + byte codePointLower = (byte) Character.toLowerCase(v.asciiByte()); + if (codePointLower == codePoint) { + result.add(v); + found = true; + cdcNumberTerminator = null; + break; + } + } + if (convertDiacritics) { + FCDotCDC1604DashP6 alias = checkDiacriticAlias(codePointStr); + if (alias != null) { + result.add(alias); + found = true; + cdcNumberTerminator = null; + break; + } + } + } + } + if (!found) { + throw new IllegalArgumentException("Unsupported char: '" + ((char)codePoint) + "' 0x" + Integer.toHexString(codePoint)); + } + } + return result; + } + + static private FCDotCDC1604DashP6 checkDiacriticAlias(String codePoint) { + if ("Æ æ Å å Ǻ ǻ Ḁ ḁ ẚ Ă ă Ặ ặ Ắ ắ Ằ ằ Ẳ ẳ Ẵ ẵ Ȃ ȃ Â â Ậ ậ Ấ ấ Ầ ầ Ẫ ẫ Ẩ ẩ Ả ả Ǎ ǎ Ⱥ ⱥ Ȧ ȧ Ǡ ǡ Ạ ạ Ä ä Ǟ ǟ À à Ȁ ȁ Á á Ā ā Ā̀ ā̀ Ã ã Ą ą Ą́ ą́ Ą̃ ą̃ A̲ a̲ ᶏ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX01_A; + } + if ("Ƀ ƀ Ḃ ḃ Ḅ ḅ Ḇ ḇ Ɓ ɓ ᵬ ᶀ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX02_B; + } + if ("Ć ć Ĉ ĉ Č č Ċ ċ Ḉ ḉ Ƈ ƈ C̈ c̈ Ȼ ȼ Ç ç Ꞔ ꞔ Ꞓ ꞓ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX03_C; + } + if ("Đ đ Ꟈ ꟈ Ɗ ɗ Ḋ ḋ Ḍ ḍ Ḑ ḑ Ḓ ḓ Ď ď Ḏ ḏ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX04_D; + } + if ("Ĕ ĕ Ḝ ḝ Ȇ ȇ Ê ê Ê̄ ê̄ Ê̌ ê̌ Ề ề Ế ế Ể ể Ễ ễ Ệ ệ Ẻ ẻ Ḙ ḙ Ě ě Ɇ ɇ Ė ė Ė́ ė́ Ė̃ ė̃ Ẹ ẹ Ë ë È è È̩ è̩ Ȅ ȅ É é É̩ Ē ē Ḕ ḕ Ḗ ḗ Ẽ ẽ Ḛ ḛ Ę ę Ę́ ę́ Ę̃ ę̃ Ȩ ȩ E̩ e̩ ᶒ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX05_E; + } + if ("Ƒ ƒ Ḟ ḟ ᵮ ᶂ Ꞙ ꞙ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX06_F; + } + if ("Ǵ ǵ Ǥ ǥ Ĝ ĝ Ǧ ǧ Ğ ğ Ģ ģ Ɠ ɠ Ġ ġ Ḡ ḡ Ꞡ ꞡ ᶃ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX07_G; + } + if ("Ĥ ĥ Ȟ ȟ Ħ ħ Ḩ ḩ Ⱨ ⱨ ẖ ẖ Ḥ ḥ Ḣ ḣ Ḧ ḧ Ḫ ḫ ꞕ Ꜧ ꜧ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX08_H; + } + if ("Ị ị Ĭ ĭ Î î Ǐ ǐ Ɨ ɨ Ï ï Ḯ ḯ Í í Ì ì Ȉ ȉ Į į Į́ Į̃ Ī ī Ī̀ ī̀ ᶖ Ỉ ỉ Ȋ ȋ Ĩ ĩ Ḭ ḭ ᶤ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX09_I; + } + if ("J́ j́ Ĵ ĵ J̌ ǰ Ɉ ɉ J̃ j̇̃".contains(codePoint)) { + return FCDotCDC1604DashP6.NX10_J; + } + if ("Ƙ ƙ Ꝁ ꝁ Ḱ ḱ Ǩ ǩ Ḳ ḳ Ķ ķ ᶄ Ⱪ ⱪ Ḵ ḵ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX11_K; + } + if ("Ĺ ĺ Ł ł Ľ ľ Ḹ ḹ L̃ l̃ Ļ ļ Ŀ ŀ Ḷ ḷ Ḻ ḻ Ḽ ḽ Ƚ ƚ Ⱡ ⱡ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX12_L; + } + if ("Ḿ ḿ Ṁ ṁ Ṃ ṃ M̃ m̃ ᵯ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX13_M; + } + if ("Ń ń Ñ ñ Ň ň Ǹ ǹ Ṅ ṅ Ṇ ṇ Ņ ņ Ṉ ṉ Ṋ ṋ Ꞥ ꞥ ᵰ ᶇ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX14_N; + } + if ("Ø ø Ǿ ǿ Ö ö Ȫ ȫ Ó ó Ò ò Ô ô Ố ố Ồ ồ Ổ ổ Ỗ ỗ Ộ ộ Ǒ ǒ Ő ő Ŏ ŏ Ȏ ȏ Ȯ ȯ Ȱ ȱ Ọ ọ Ɵ ɵ ᶱ Ơ ơ Ớ ớ Ờ ờ Ỡ ỡ Ợ ợ Ở ở Ỏ ỏ Ō ō Ṓ ṓ Ṑ ṑ Õ õ Ȭ ȭ Ṍ ṍ Ṏ ṏ Ǫ ǫ Ȍ ȍ O̩ o̩ Ó̩ ó̩ Ò̩ ò̩ Ǭ ǭ O͍ o͍".contains(codePoint)) { + return FCDotCDC1604DashP6.NX15_O; + } + if ("Ṕ ṕ Ṗ ṗ Ᵽ ᵽ Ƥ ƥ ᵱ ᶈ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX16_P; + } + if ("ʠ Ɋ ɋ q̃".contains(codePoint)) { + return FCDotCDC1604DashP6.NX17_Q; + } + if ("Ŕ ŕ Ɍ ɍ Ř ř Ŗ ŗ Ṙ ṙ Ȑ ȑ Ȓ ȓ Ṛ ṛ Ṝ ṝ Ṟ ṟ Ꞧ ꞧ Ɽ ɽ R̃ r̃ ᵲ ꭨ ᵳ ᶉ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX18_R; + } + if ("Ś ś Ṡ ṡ ẛ Ṩ ṩ Ṥ ṥ Ṣ ṣ S̩ s̩ Ꞩ ꞩ Ꟊ ꟊ Ꟍ ꟍ Ŝ ŝ Ṧ ṧ Š š Ş ş Ș ș S̈ s̈ ᶊ Ȿ ȿ ᵴ ᶳ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX19_S; + } + if ("Ť ť Ṫ ṫ ẗ Ţ ţ Ṭ ṭ Ʈ ʈ Ț ț ƫ Ṱ ṱ Ṯ ṯ Ŧ ŧ Ⱦ ⱦ Ƭ ƭ ᵵ ᶵ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX20_T; + } + if ("Ŭ ŭ Ʉ ʉ ᵾ ᶶ Ꞹ ꞹ Ụ ụ Ü ü Ǜ ǜ Ǘ ǘ Ǚ ǚ Ǖ ǖ Ṳ ṳ Ú ú Ù ù Û û Ṷ ṷ Ǔ ǔ Ȗ ȗ Ű ű Ŭ ŭ Ư ư Ứ ứ Ừ ừ Ử ử Ự ự Ữ Ữ Ủ ủ Ū ū Ū̀ ū̀ Ū́ ū́ Ṻ ṻ Ū̃ ū̃ Ũ ũ Ṹ ṹ Ṵ ṵ ᶙ Ų ų Ų́ ų́ Ų̃ ų̃ Ȕ ȕ Ů ů".contains(codePoint)) { + return FCDotCDC1604DashP6.NX21_U; + } + if ("Ṽ ṽ Ṿ ṿ Ʋ ʋ ᶌ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX22_V; + } + if ("Ẃ ẃ Ẁ ẁ Ŵ ŵ Ẅ ẅ Ẇ ẇ Ẉ ẉ ẘ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX23_W; + } + if ("Ẍ ẍ Ẋ ẋ X̂ x̂ ᶍ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX24_X; + } + if ("Ý ý Ỳ ỳ Ŷ ŷ Ÿ ÿ Ỹ ỹ Ẏ ẏ Ỵ ỵ ẙ Ỷ ỷ Ȳ ȳ Ɏ ɏ Ƴ ƴ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX25_Y; + } + if ("Ź ź Ẑ ẑ Ž ž Ż ż Ẓ ẓ Ẕ ẕ Ƶ ƶ ᵶ Ᶎ ᶎ Ⱬ ⱬ".contains(codePoint)) { + return FCDotCDC1604DashP6.NX26_Z; + } + if ("& ⅋ 🙰 🙱 🙲 🙳 🙴 🙵".contains(codePoint)) { + return FCDotCDC1604DashP6.NX27_AMPERSAND; + } + return null; + } +} diff --git a/nx01-x4o-o2o/src/test/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6Test.java b/nx01-x4o-o2o/src/test/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6Test.java index fb7d4c9..f92a38a 100644 --- a/nx01-x4o-o2o/src/test/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6Test.java +++ b/nx01-x4o-o2o/src/test/java/org/x4o/o2o/fc18/FCDotCDC1604DashP6Test.java @@ -57,7 +57,7 @@ public class FCDotCDC1604DashP6Test { @Test public void testAsciiSimple() throws Exception { - List cdc = FCDotCDC1604DashP6.convertFromUnicode("foobar"); + List cdc = FourCornerUnicodeImport.lossy().convertToP6("foobar"); Assertions.assertNotNull(cdc); Assertions.assertFalse(cdc.isEmpty()); Assertions.assertEquals(6, cdc.size()); @@ -68,13 +68,45 @@ public class FCDotCDC1604DashP6Test { Assertions.assertEquals(FCDotCDC1604DashP6.NX01_A, cdc.get(4)); Assertions.assertEquals(FCDotCDC1604DashP6.NX18_R, cdc.get(5)); - String out = FCDotCDC1604DashP6.convertToUnicode(cdc); + String out = FourCornerUnicodeDisplay.simple().renderFromP6(cdc); Assertions.assertEquals("FOOBAR", out); } + @Test + public void testCheckDiacritics() throws Exception { + String foobar = "ꞘȍőḆẬř"; + List cdc = FourCornerUnicodeImport.lossy().convertToP6(foobar); + Assertions.assertNotNull(cdc); + Assertions.assertFalse(cdc.isEmpty()); + Assertions.assertEquals("FOOBAR", FourCornerUnicodeDisplay.simple().renderFromP6(cdc)); + Assertions.assertEquals("foobar", FourCornerUnicodeDisplay.mixed().renderFromP6(cdc)); + Assertions.assertThrows(IllegalArgumentException.class, () -> { + FourCornerUnicodeImport.strict().convertToP6(foobar); + }); + } + + @Test + public void testMixedCasing() throws Exception { + List cdc = new ArrayList<>(); + cdc.add(FCDotCDC1604DashP6.NX01_A); + cdc.add(FCDotCDC1604DashP6.__SPACE); + cdc.add(FCDotCDC1604DashP6.NX02_B); + cdc.add(FCDotCDC1604DashP6.__GLUE); + cdc.add(FCDotCDC1604DashP6.NX03_C); + cdc.add(FCDotCDC1604DashP6.NX04_D); + cdc.add(FCDotCDC1604DashP6._DOT); + cdc.add(FCDotCDC1604DashP6.__GLUE); + cdc.add(FCDotCDC1604DashP6.NX10_J); + cdc.add(FCDotCDC1604DashP6.NX11_K); + + Assertions.assertEquals("A BCD.JK", FourCornerUnicodeDisplay.simple().renderFromP6(cdc)); + Assertions.assertEquals("a bCd.Jk", FourCornerUnicodeDisplay.mixed().renderFromP6(cdc)); + Assertions.assertEquals("a bᐧCd.Jk", FourCornerUnicodeDisplay.mixedᐧEskimo().renderFromP6(cdc)); + } + @Test public void testNumber012() throws Exception { - List cdc = FCDotCDC1604DashP6.convertFromUnicode("01201337"); + List cdc = FourCornerUnicodeImport.lossy().convertToP6("01201337"); Assertions.assertNotNull(cdc); Assertions.assertFalse(cdc.isEmpty()); Assertions.assertEquals(16, cdc.size()); @@ -95,7 +127,7 @@ public class FCDotCDC1604DashP6Test { Assertions.assertEquals(FCDotCDC1604DashP6.NX03_C, cdc.get(14)); // 3 Assertions.assertEquals(FCDotCDC1604DashP6.NX07_G, cdc.get(15)); // 7 - String out = FCDotCDC1604DashP6.convertToUnicode(cdc); + String out = FourCornerUnicodeDisplay.simple().renderFromP6(cdc); Assertions.assertEquals("01201337", out); } @@ -110,7 +142,7 @@ public class FCDotCDC1604DashP6Test { cdc.add(FCDotCDC1604DashP6._AT); cdc.add(FCDotCDC1604DashP6.NX11_K); // = K - String out = FCDotCDC1604DashP6.convertToUnicode(cdc); + String out = FourCornerUnicodeDisplay.simple().renderFromP6(cdc); Assertions.assertEquals("X^%@K", out); } @@ -125,13 +157,13 @@ public class FCDotCDC1604DashP6Test { cdc.add(FCDotCDC1604DashP6.NX03_C); // = 3 cdc.add(FCDotCDC1604DashP6.NX10_J); // = J - String out = FCDotCDC1604DashP6.convertToUnicode(cdc); + String out = FourCornerUnicodeDisplay.simple().renderFromP6(cdc); Assertions.assertEquals("B3J", out); } @Test public void testLineEndings() throws Exception { - List cdc = FCDotCDC1604DashP6.convertFromUnicode("A\nB\rC\r\nD\n"); + List cdc = FourCornerUnicodeImport.strict().convertToP6("A\nB\rC\r\nD\n"); Assertions.assertNotNull(cdc); Assertions.assertFalse(cdc.isEmpty()); Assertions.assertEquals(8, cdc.size()); @@ -144,7 +176,7 @@ public class FCDotCDC1604DashP6Test { Assertions.assertEquals(FCDotCDC1604DashP6.NX04_D, cdc.get(6)); Assertions.assertEquals(FCDotCDC1604DashP6.__LINE, cdc.get(7)); - String out = FCDotCDC1604DashP6.convertToUnicode(cdc); + String out = FourCornerUnicodeDisplay.simple().renderFromP6(cdc); Assertions.assertEquals("A\nB\nC\nD\n", out); } }