Split FC unicode import and display code from P6 enum

This commit is contained in:
Willem Cazander 2024-12-28 15:33:10 +01:00
parent 4b8439a55c
commit 8c8ed675ac
5 changed files with 489 additions and 207 deletions

View file

@ -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 attrX8 : sectionX8.getAttributes()) {
fieldX18 = sectionX18.makeAttribute(toX8(attrX8.getName()), toX8(attrX8.getBody()));
for (String remark : attrX8.getRemarks()) {
fieldX18.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());
}
}
return result;
}
static private void convertRemarks(WarpManifestX18HeaderField field, List<String> remarks) {
for (String remark : remarks) {
field.withRemark(convertX8(remark));
}
}
static private PrimordialOctalOrangeJuiceCord convertX8(String value) {
List<FCDotCDC1604DashP6> fc18 = FCDotCDC1604DashP6.convertFromUnicode(value);
List<Integer> fc18Num = fc18.stream().map(v -> v.ordinal()).toList();
return PrimordialOctalOrangeString.valueOfSmurfs(fc18Num);
static private PrimordialOctalOrangeJuiceCord toX8(String value) {
return FourCornerUnicodeImport.lossy().convertToJuice(value);
}
}

View file

@ -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<FCDotCDC1604DashP6> convertFromUnicode(String text) {
return convertFromUnicode(text, false);
static public int length() {
return P6_ALL.length;
}
static public List<FCDotCDC1604DashP6> convertFromUnicode(String text, boolean strict) {
String textSingleNewLines = text.replaceAll("\r\n", "\n");
PrimitiveIterator.OfInt i = textSingleNewLines.codePoints().iterator();
List<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> cdcChars) {
StringBuilder buf = new StringBuilder();
Iterator<FCDotCDC1604DashP6> 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];
}
}

View file

@ -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<StringBuilder> appender) {
StringBuilder buf = new StringBuilder();
appender.accept(buf);
return buf.toString();
}
public String renderFromP6(List<FCDotCDC1604DashP6> chars) {
return buildString(v -> renderFromP6(chars, v));
}
public void renderFromP6(List<FCDotCDC1604DashP6> 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<Integer> int18 = new ArrayList<>();
chars.juiceForEach(v -> int18.add(v.baitOctalNumber()));
renderFromInt18(int18, buf);
}
public String renderFromInt18(List<Integer> chars) {
return buildString(v -> renderFromInt18(chars, v));
}
public void renderFromInt18(List<Integer> chars, StringBuilder buf) {
Iterator<Integer> 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);
}
}
}

View file

@ -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<Integer> convertToInt18(String text) {
return convertToP6(text).stream().map(v -> v.ordinal()).toList();
}
public List<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> 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;
}
}

View file

@ -57,7 +57,7 @@ public class FCDotCDC1604DashP6Test {
@Test
public void testAsciiSimple() throws Exception {
List<FCDotCDC1604DashP6> cdc = FCDotCDC1604DashP6.convertFromUnicode("foobar");
List<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> cdc = FCDotCDC1604DashP6.convertFromUnicode("01201337");
List<FCDotCDC1604DashP6> 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<FCDotCDC1604DashP6> cdc = FCDotCDC1604DashP6.convertFromUnicode("A\nB\rC\r\nD\n");
List<FCDotCDC1604DashP6> 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);
}
}