/*
This file is part of jpcsp.
Jpcsp is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jpcsp is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jpcsp. If not, see <http://www.gnu.org/licenses/>.
*/
package jpcsp.HLE.modules;
import java.nio.charset.Charset;
import java.util.SortedMap;
import org.apache.log4j.Logger;
import jpcsp.HLE.HLEFunction;
import jpcsp.HLE.HLEModule;
import jpcsp.HLE.HLEUnimplemented;
import jpcsp.HLE.Modules;
import jpcsp.HLE.TPointer;
import jpcsp.HLE.TPointer32;
import jpcsp.memory.IMemoryReader;
import jpcsp.memory.IMemoryWriter;
import jpcsp.memory.MemoryReader;
import jpcsp.memory.MemoryWriter;
public class sceCcc extends HLEModule {
public static Logger log = Modules.getLogger("sceCcc");
protected static final Charset charsetUTF8 = getCharset("UTF-8");
protected static final Charset charsetUTF16 = getCharset("UTF-16LE");
protected static final Charset charsetSJIS = getCharset("Shift_JIS");
protected int errorCharUTF8;
protected int errorCharUTF16;
protected int errorCharSJIS;
@Override
public void stop() {
errorCharUTF8 = 0;
errorCharUTF16 = 0;
errorCharSJIS = 0;
super.stop();
}
protected static Charset getCharset(String charsetName) {
if (!Charset.isSupported(charsetName)) {
log.warn(String.format("Charset not supported by this JVM: %s", charsetName));
if (log.isInfoEnabled()) {
SortedMap<String, Charset> availableCharsets = Charset.availableCharsets();
log.info("Supported Charsets:");
for (String availableCharsetName : availableCharsets.keySet()) {
log.info(availableCharsetName);
}
}
return Charset.defaultCharset();
}
return Charset.forName(charsetName);
}
protected static byte[] addByteToArray(byte[] array, byte b) {
byte[] newArray = new byte[array.length + 1];
System.arraycopy(array, 0, newArray, 0, array.length);
newArray[array.length] = b;
return newArray;
}
protected static byte[] getBytesUTF16(int addr) {
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, 2);
byte[] bytes = new byte[0];
while (true) {
int utf16 = memoryReader.readNext();
if (utf16 == 0) {
break;
}
bytes = addByteToArray(bytes, (byte) utf16);
bytes = addByteToArray(bytes, (byte) (utf16 >> 8));
}
return bytes;
}
protected static String getStringUTF16(int addr) {
return new String(getBytesUTF16(addr), charsetUTF16);
}
protected static byte[] getBytesUTF8(int addr) {
IMemoryReader memoryReader = MemoryReader.getMemoryReader(addr, 1);
byte[] bytes = new byte[0];
while (true) {
int utf8 = memoryReader.readNext();
if (utf8 == 0) {
break;
}
bytes = addByteToArray(bytes, (byte) utf8);
}
return bytes;
}
protected static String getStringUTF8(int addr) {
return new String(getBytesUTF8(addr), charsetUTF8);
}
protected static String getStringSJIS(int addr) {
return new String(getBytesUTF8(addr), charsetSJIS);
}
protected int writeStringBytes(byte[] bytes, int addr, int maxSize, int trailingNulls) {
int bytesWritten = 0;
IMemoryWriter memoryWriter = MemoryWriter.getMemoryWriter(addr, 1);
if (bytes != null) {
int length = Math.min(bytes.length, maxSize - 1);
for (int i = 0; i < length; i++) {
memoryWriter.writeNext(bytes[i] & 0xFF);
}
bytesWritten += length;
}
// write trailing '\0'
for (int i = 0; i < trailingNulls; i++) {
memoryWriter.writeNext(0);
}
memoryWriter.flush();
return bytesWritten;
}
@HLEUnimplemented
@HLEFunction(nid = 0x00D1378F, version = 150)
public int sceCccUTF8toUTF16() {
return 0;
}
@HLEFunction(nid = 0x068C4320, version = 150)
public int sceCccEncodeSJIS(TPointer32 dstAddr, int ucs4char) {
char[] chars = Character.toChars(ucs4char);
if (chars == null) {
return 0;
}
String s = new String(chars);
byte[] bytes = s.getBytes(charsetSJIS);
int addr = dstAddr.getValue();
int length = writeStringBytes(bytes, addr, 100, 0);
dstAddr.setValue(addr + length);
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccEncodeSJIS encoding '%s' into %d bytes", s, length));
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x0A00ECF9, version = 150)
public int sceCccSwprintfSJIS() {
return 0;
}
@HLEFunction(nid = 0x17E1D813, version = 150)
public int sceCccSetErrorCharUTF8(int errorChar) {
int previousErrorChar = errorCharUTF8;
errorCharUTF8 = errorChar;
return previousErrorChar;
}
@HLEUnimplemented
@HLEFunction(nid = 0x3AEC5274, version = 150)
public int sceCccSwprintfUTF8() {
return 0;
}
@HLEFunction(nid = 0x41B724A5, version = 150)
public int sceCccUTF16toUTF8(TPointer dstAddr, int dstSize, TPointer srcAddr) {
String dstString = getStringUTF16(srcAddr.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccUTF16toUTF8 string='%s'", dstString));
}
byte[] dstBytes = dstString.getBytes(charsetUTF8);
return writeStringBytes(dstBytes, dstAddr.getAddress(), dstSize, 1);
}
@HLEFunction(nid = 0x4BDEB2A8, version = 150)
public int sceCccStrlenUTF16(TPointer strUTF16) {
String str = getStringUTF16(strUTF16.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccStrlenUTF16 str='%s'", str));
}
return str.length();
}
@HLEUnimplemented
@HLEFunction(nid = 0x67BF0D19, version = 150)
public int sceCccIsValidSJIS() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x6CBB36A0, version = 150)
public int sceCccVswprintfUTF8() {
return 0;
}
@HLEFunction(nid = 0x6F82EE03, version = 150)
public int sceCccUTF8toSJIS(TPointer dstAddr, int dstSize, TPointer srcAddr) {
String dstString = getStringUTF8(srcAddr.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccUTF8toSJIS string='%s'", dstString));
}
byte[] dstBytes = dstString.getBytes(charsetSJIS);
return writeStringBytes(dstBytes, dstAddr.getAddress(), dstSize, 1);
}
@HLEUnimplemented
@HLEFunction(nid = 0x70ECAA10, version = 150)
public int sceCccUCStoJIS() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x76E33E9C, version = 150)
public int sceCccIsValidUCS2() {
return 0;
}
@HLEFunction(nid = 0x8406F469, version = 150)
public int sceCccEncodeUTF16(TPointer32 dstAddr, int ucs4char) {
char[] chars = Character.toChars(ucs4char);
if (chars == null) {
return 0;
}
String s = new String(chars);
byte[] bytes = s.getBytes(charsetUTF16);
int addr = dstAddr.getValue();
int length = writeStringBytes(bytes, addr, 100, 0);
dstAddr.setValue(addr + length);
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccEncodeUTF16 encoding '%s' into %d bytes", s, length));
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x90521AC5, version = 150)
public int sceCccIsValidUTF8() {
return 0;
}
@HLEFunction(nid = 0x92C05851, version = 150)
public int sceCccEncodeUTF8(TPointer32 dstAddr, int ucs4char) {
char[] chars = Character.toChars(ucs4char);
if (chars == null) {
return 0;
}
String s = new String(chars);
byte[] bytes = s.getBytes(charsetUTF8);
int addr = dstAddr.getValue();
int length = writeStringBytes(bytes, addr, 100, 0);
dstAddr.setValue(addr + length);
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccEncodeUTF8 encoding '%s' into %d bytes", s, length));
}
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0x953E6C10, version = 150)
public int sceCccDecodeSJIS() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xA2D5D209, version = 150)
public int sceCccIsValidJIS() {
return 0;
}
@HLEFunction(nid = 0xA62E6E80, version = 150)
public int sceCccSJIStoUTF8(TPointer dstUTF8, int dstSize, TPointer srcSJIS) {
String str = getStringSJIS(srcSJIS.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccSJIStoUTF8 str='%s'", str));
}
byte[] bytesUTF8 = str.getBytes(charsetUTF8);
return writeStringBytes(bytesUTF8, dstUTF8.getAddress(), dstSize, 1);
}
@HLEUnimplemented
@HLEFunction(nid = 0xB4D1CBBF, version = 150)
public int sceCccSetTable(TPointer jis2ucs, TPointer ucs2jis) {
// Both tables jis2ucs and ucs2jis have a size of 0x20000 bytes
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xB7D3C112, version = 150)
public int sceCccStrlenUTF8(TPointer strUTF8) {
String str = getStringUTF16(strUTF8.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccStrlenUTF8 str='%s'", str));
}
return str.length();
}
@HLEFunction(nid = 0xB8476CF4, version = 150)
public int sceCccSetErrorCharUTF16(int errorChar) {
int previousErrorChar = errorCharUTF16;
errorCharUTF16 = errorChar;
return previousErrorChar;
}
@HLEUnimplemented
@HLEFunction(nid = 0xBD11EEF3, version = 150)
public int sceCccIsValidUnicode() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xBDC4D699, version = 150)
public int sceCccVswprintfSJIS() {
return 0;
}
@HLEFunction(nid = 0xBEB47224, version = 150)
public int sceCccSJIStoUTF16(TPointer dstUTF16, int dstSize, TPointer srcSJIS) {
String str = getStringSJIS(srcSJIS.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccSJIStoUTF16 str='%s'", str));
}
byte[] bytesUTF16 = str.getBytes(charsetUTF16);
return writeStringBytes(bytesUTF16, dstUTF16.getAddress(), dstSize, 2);
}
@HLEUnimplemented
@HLEFunction(nid = 0xC56949AD, version = 150)
public int sceCccSetErrorCharSJIS(int errorChar) {
int previousErrorChar = errorCharSJIS;
errorCharSJIS = errorChar;
return previousErrorChar;
}
@HLEFunction(nid = 0xC6A8BEE2, version = 150)
public int sceCccDecodeUTF8(TPointer32 srcAddrUTF8) {
String srcString = getStringUTF8(srcAddrUTF8.getValue());
int codePoint = srcString.codePointAt(0);
int codePointSize = Character.charCount(codePoint);
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccDecodeUTF8 string='%s'(0x%08X), codePoint=0x%X(size=%d)", srcString, srcAddrUTF8.getValue(), codePoint, codePointSize));
}
srcAddrUTF8.setValue(srcAddrUTF8.getValue() + codePointSize);
return codePoint;
}
@HLEUnimplemented
@HLEFunction(nid = 0xCC0A8BDA, version = 150)
public int sceCccIsValidUTF16() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xD2B18485, version = 150)
public int sceCccIsValidUCS4() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xD9392CCB, version = 150)
public int sceCccStrlenSJIS(TPointer strSJIS) {
String str = getStringUTF16(strSJIS.getAddress());
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccStrlenSJIS str='%s'", str));
}
return str.length();
}
@HLEFunction(nid = 0xE0CF8091, version = 150)
public int sceCccDecodeUTF16(TPointer32 srcAddrUTF16) {
String srcString = getStringUTF16(srcAddrUTF16.getValue());
int codePoint = srcString.codePointAt(0);
int codePointSize = Character.charCount(codePoint);
if (log.isDebugEnabled()) {
log.debug(String.format("sceCccDecodeUTF16 string='%s'(0x%08X), codePoint=0x%X(size=%d)", srcString, srcAddrUTF16.getValue(), codePoint, codePointSize));
}
srcAddrUTF16.setValue(srcAddrUTF16.getValue() + (codePointSize << 1));
return codePoint;
}
@HLEUnimplemented
@HLEFunction(nid = 0xF1B73D12, version = 150)
public int sceCccUTF16toSJIS() {
return 0;
}
@HLEUnimplemented
@HLEFunction(nid = 0xFB7846E2, version = 150)
public int sceCccJIStoUCS() {
return 0;
}
}