Commit 98f05e19 authored by Stephanie Gawroriski's avatar Stephanie Gawroriski
Browse files

Implement decoding of Shift-JIS double byte characters.

parent 3aaa84fc
Pipeline #87052 passed with stages
in 1 minute and 27 seconds
......@@ -8,6 +8,7 @@
package cc.squirreljme.jvm.launch;
import cc.squirreljme.jvm.mle.JarPackageShelf;
import cc.squirreljme.jvm.mle.RuntimeShelf;
import cc.squirreljme.jvm.mle.brackets.JarPackageBracket;
import cc.squirreljme.jvm.mle.constants.PhoneModelType;
......@@ -114,7 +115,16 @@ public class IModeApplication
String appClass = this._adfProps.get(IModeApplication._APP_CLASS);
if (appName != null)
{
// If the application name contains an invalid character then
// it is an unsupported character we do not know about
if (appName.indexOf(0xFFFD) >= 0)
return appName + " (" +
JarPackageShelf.libraryPath(this.jar) + ")";
return appName;
}
return (appClass != null ? appClass : "Invalid i-mode Application");
}
......
// ---------------------------------------------------------------------------
// SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the GNU General Public License v3+, or later.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package cc.squirreljme.runtime.cldc.io;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
/**
* Table for use with double byte characters.
*
* The table is in the following format:
* - For every valid A byte:
* - {@code uint8_t} The actual A byte.
* - {@code uint8_t} The number of B characters for the A byte.
* - Then for every B byte:
* - {@code uint8_t} The B byte.
* - {@code uint16_t} The 16-bit unicode value of the character.
*
* @since 2022/02/14
*/
public final class DoubleByteTable
{
/** The "A" byte Table. */
private final __BTable__[] _aTable;
/**
* Initializes the double byte table.
*
* @param __aTable The "A" byte Table.
* @throws IndexOutOfBoundsException If the table size is not valid.
* @throws NullPointerException On null arguments.
* @since 2022/02/14
*/
private DoubleByteTable(__BTable__[] __aTable)
throws IndexOutOfBoundsException, NullPointerException
{
if (__aTable == null)
throw new NullPointerException("NARG");
if (__aTable.length != 256)
throw new IndexOutOfBoundsException("IOOB");
this._aTable = __aTable;
}
/**
* Decodes a double byte shift-jis character.
*
* @param __a The first byte.
* @param __b The second byte.
* @return The decoded character, will return a negative value if unknown.
* @since 2022/02/14
*/
public int decode(byte __a, byte __b)
{
// Find the B table for the A character
__BTable__ bTable = this._aTable[__a & 0xFF];
// Is there no BTable?
if (bTable == null)
return -1;
// Find the B character
return bTable.decode(__b);
}
/**
* Loads the double byte table.
*
* @return The double byte table.
* @throws IOException On read errors.
* @throws NullPointerException On null arguments.
* @since 2022/02/14
*/
public static DoubleByteTable loadTable(InputStream __in)
throws IOException, NullPointerException
{
if (__in == null)
throw new NullPointerException("NARG");
// We use a specific format for this
DataInputStream in = new DataInputStream(__in);
// The resultant A Table
__BTable__[] aTable = new __BTable__[256];
// Load in the various B Tables
for (;;)
{
// Read the A byte this belongs to
int aByte = in.read();
// EOF?
if (aByte < 0)
break;
// Read the number of characters in the "B" tread
int numChars = in.readUnsignedByte();
// Setup arrays for the B tread
short[] bBytes = new short[numChars];
char[] bChars = new char[numChars];
// Read the characters available
for (int i = 0; i < numChars; i++)
{
bBytes[i] = (short)in.readUnsignedByte();
bChars[i] = in.readChar();
}
// Add this tread
aTable[aByte] = new __BTable__(bBytes, bChars);
}
// Setup final table
return new DoubleByteTable(aTable);
}
/**
* Represents an A-table within the Shift-JIS Table.
*
* @since 2022/02/14
*/
private static final class __BTable__
{
/** The B bytes. */
private final short[] _bBytes;
/** The B characters. */
private final char[] _bChars;
/**
* Initializes the individual B table.
*
* @param __bBytes The B bytes.
* @param __bChars The B characters.
* @throws IllegalArgumentException If the arrays are of different
* length.
* @throws NullPointerException On null arguments.
* @since 2022/02/14
*/
__BTable__(short[] __bBytes, char[] __bChars)
throws IllegalArgumentException, NullPointerException
{
if (__bBytes == null || __bChars == null)
throw new NullPointerException("NARG");
if (__bBytes.length != __bChars.length)
throw new IllegalArgumentException("IAEE");
this._bBytes = __bBytes;
this._bChars = __bChars;
}
/**
* Decodes the B value.
*
* @param __b The B character.
* @return The decoded character or a negative value if not valid.
* @since 2022/02/14
*/
public int decode(byte __b)
{
// Find the index of the character
int index = Arrays.binarySearch(this._bBytes, (short)(__b & 0xFF));
if (index < 0)
return -1;
// Return the character it is
return this._bChars[index];
}
}
}
......@@ -9,6 +9,9 @@
package cc.squirreljme.runtime.cldc.io;
import java.io.IOException;
import java.io.InputStream;
/**
* Decoder for Shift-JIS.
*
......@@ -20,6 +23,9 @@ package cc.squirreljme.runtime.cldc.io;
public class ShiftJisDecoder
implements Decoder
{
/** The loaded Shift-JIS table. */
private static volatile DoubleByteTable _TABLE;
/**
* {@inheritDoc}
* @since 2021/06/13
......@@ -48,7 +54,7 @@ public class ShiftJisDecoder
return -1;
// Standard ASCII
int a = __b[0] & 0xFF;
int a = __b[__o] & 0xFF;
if (a <= 0x7F)
{
// Yen
......@@ -73,11 +79,12 @@ public class ShiftJisDecoder
if (__l < 2)
return -1;
// Unknown two-byte sequence
return 0xFFFD | 0x2_0000;
// Decode
int z = ShiftJisDecoder.loadTable().decode((byte)a, __b[__o + 1]);
return (z < 0 ? 0xFFFD : z) | 0x2_0000;
}
// TODO: Decode more characters
// Unknown or invalid character
return 0xFFFD | 0x1_0000;
}
......@@ -180,4 +187,35 @@ public class ShiftJisDecoder
return 0xFFFD;
}
/**
* Loads the table for Shift-JIS.
*
* @return The read table.
* @since 2022/02/14
*/
public static DoubleByteTable loadTable()
{
// Already read?
DoubleByteTable rv = ShiftJisDecoder._TABLE;
if (rv != null)
return rv;
// Load in the table
try (InputStream in = DoubleByteTable.class.getResourceAsStream(
"shiftjis.double"))
{
// Load the table in
rv = DoubleByteTable.loadTable(in);
// Cache and use it
ShiftJisDecoder._TABLE = rv;
return rv;
}
catch (IOException e)
{
// {@squirreljme.error ZZ4i Could not load the Shift-JIS table.}
throw new RuntimeException("ZZ4i", e);
}
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment