/* 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 static jpcsp.Allegrex.Common._a2; import static jpcsp.Allegrex.Common._a3; import org.apache.log4j.Logger; import jpcsp.Allegrex.CpuState; import jpcsp.Allegrex.compiler.nativeCode.AbstractNativeCodeSequence; import jpcsp.HLE.BufferInfo; import jpcsp.HLE.CanBeNull; import jpcsp.HLE.HLEFunction; import jpcsp.HLE.HLEModule; import jpcsp.HLE.Modules; import jpcsp.HLE.PspString; import jpcsp.HLE.TPointer; import jpcsp.HLE.TPointer32; import jpcsp.HLE.BufferInfo.LengthInfo; import jpcsp.HLE.BufferInfo.Usage; import jpcsp.memory.IMemoryReader; import jpcsp.memory.MemoryReader; import jpcsp.util.Utilities; public class SysclibForKernel extends HLEModule { public static Logger log = Modules.getLogger("SysclibForKernel"); private static final String validNumberCharactersUpperCase = "0123456789ABCDEF"; private static final String validNumberCharactersLowerCase = "0123456789abcdef"; @HLEFunction(nid = 0x10F3BB61, version = 150) public int memset(@CanBeNull TPointer destAddr, int data, int size) { if (destAddr.isNotNull()) { destAddr.memset((byte) data, size); } return 0; } @HLEFunction(nid = 0xEC6F1CF2, version = 150) public int strcpy(@CanBeNull TPointer destAddr, @CanBeNull TPointer srcAddr) { if (destAddr.isNotNull() && srcAddr.isNotNull()) { AbstractNativeCodeSequence.strcpy(destAddr.getAddress(), srcAddr.getAddress()); } return 0; } @HLEFunction(nid = 0xC0AB8932, version = 150) public int strcmp(@CanBeNull TPointer src1Addr, @CanBeNull TPointer src2Addr) { if (log.isDebugEnabled()) { log.debug(String.format("strcmp '%s', '%s'", Utilities.readStringZ(src1Addr.getAddress()), Utilities.readStringZ(src2Addr.getAddress()))); } return AbstractNativeCodeSequence.strcmp(src1Addr.getAddress(), src2Addr.getAddress()); } @HLEFunction(nid = 0x52DF196C, version = 150) public int strlen(@CanBeNull TPointer srcAddr) { return AbstractNativeCodeSequence.getStrlen(srcAddr.getAddress()); } @HLEFunction(nid = 0x81D0D1F7, version = 150) public int memcmp(TPointer src1Addr, TPointer src2Addr, int size) { int result = 0; if (size > 0) { IMemoryReader memoryReader1 = MemoryReader.getMemoryReader(src1Addr.getAddress(), size, 1); IMemoryReader memoryReader2 = MemoryReader.getMemoryReader(src2Addr.getAddress(), size, 1); for (int i = 0; i < size; i++) { int c1 = memoryReader1.readNext(); int c2 = memoryReader2.readNext(); if (c1 != c2) { result = c1 < c2 ? -1 : 1; break; } } } return result; } @HLEFunction(nid = 0xAB7592FF, version = 150) public int memcpy(@CanBeNull TPointer destAddr, TPointer srcAddr, int size) { if (destAddr.isNotNull() && destAddr.getAddress() != srcAddr.getAddress()) { destAddr.getMemory().memcpyWithVideoCheck(destAddr.getAddress(), srcAddr.getAddress(), size); } return destAddr.getAddress(); } @HLEFunction(nid = 0x7AB35214, version = 150) public int strncmp(@CanBeNull TPointer src1Addr, TPointer src2Addr, int size) { int result = 0; if (size > 0) { IMemoryReader memoryReader1 = MemoryReader.getMemoryReader(src1Addr.getAddress(), size, 1); IMemoryReader memoryReader2 = MemoryReader.getMemoryReader(src2Addr.getAddress(), size, 1); if (memoryReader1 != null && memoryReader2 != null) { for (int i = 0; i < size; i++) { int c1 = memoryReader1.readNext(); int c2 = memoryReader2.readNext(); if (c1 != c2) { result = c1 - c2; break; } else if (c1 == 0) { // c1 == 0 and c2 == 0 break; } } } } return result; } @HLEFunction(nid = 0xA48D2592, version = 150) public int memmove(@CanBeNull TPointer destAddr, TPointer srcAddr, int size) { if (destAddr.isNotNull() && destAddr.getAddress() != srcAddr.getAddress()) { destAddr.getMemory().memmove(destAddr.getAddress(), srcAddr.getAddress(), size); } return 0; } @HLEFunction(nid = 0x7661E728, version = 150) public int sprintf(CpuState cpu, TPointer buffer, String format) { String formattedString = Modules.SysMemUserForUserModule.hleKernelSprintf(cpu, format, _a2); Utilities.writeStringZ(buffer.getMemory(), buffer.getAddress(), formattedString); if (log.isDebugEnabled()) { log.debug(String.format("sprintf returning '%s'", formattedString)); } return formattedString.length(); } /** * Returns a pointer to the first occurrence of s2 in s1, or a null pointer if s2 is not part of s1. * The matching process does not include the terminating null-characters, but it stops there. * @param s1 string to be scanned * @param s2 string containing the sequence of characters to match * @return a pointer to the first occurrence in s1 or the entire sequence of characters specified in s2, * or a null pointer if the sequence is not present in s1. */ @HLEFunction(nid = 0x0D188658, version = 150) public int strstr(PspString s1, PspString s2) { int index = s1.getString().indexOf(s2.getString()); if (index < 0) { return 0; } return s1.getAddress() + index; } @HLEFunction(nid = 0x476FD94A, version = 150) public int strcat(@CanBeNull TPointer destAddr, @CanBeNull TPointer srcAddr) { if (destAddr.isNull() || srcAddr.isNull()) { return 0; } int dstLength = AbstractNativeCodeSequence.getStrlen(destAddr.getAddress()); int srcLength = AbstractNativeCodeSequence.getStrlen(srcAddr.getAddress()); destAddr.memcpy(dstLength, srcAddr.getAddress(), srcLength + 1); return destAddr.getAddress(); } @HLEFunction(nid = 0xC2145E80, version = 150) public int snprintf(CpuState cpu, TPointer buffer, int n, String format) { String formattedString = Modules.SysMemUserForUserModule.hleKernelSprintf(cpu, format, _a3); if (formattedString.length() >= n) { formattedString = formattedString.substring(0, n - 1); } Utilities.writeStringZ(buffer.getMemory(), buffer.getAddress(), formattedString); if (log.isDebugEnabled()) { log.debug(String.format("snprintf returning '%s'", formattedString)); } return formattedString.length(); } private boolean isNumberValidCharacter(int c, int base) { if (base > validNumberCharactersUpperCase.length()) { base = validNumberCharactersUpperCase.length(); } if (validNumberCharactersUpperCase.substring(0, base).indexOf(c) >= 0) { return true; } if (validNumberCharactersLowerCase.substring(0, base).indexOf(c) >= 0) { return true; } return false; } @HLEFunction(nid = 0x47DD934D, version = 150) public int strtol(@CanBeNull PspString string, @CanBeNull TPointer32 endString, int base) { // base == 0 seems to be handled as base == 10. if (base == 0) { base = 10; } IMemoryReader memoryReader = MemoryReader.getMemoryReader(string.getAddress(), 1); String s = string.getString(); for (int i = 0; true; i++) { int c = memoryReader.readNext(); if (c == 0 || !isNumberValidCharacter(c, base)) { endString.setValue(memoryReader.getCurrentAddress()); s = s.substring(0, i); break; } } int result = Integer.parseInt(s, base); if (log.isDebugEnabled()) { log.debug(String.format("strtol on '%s' returning 0x%X", s, result)); } return result; } @HLEFunction(nid = 0x6A7900E1, version = 150) public int strtoul(@CanBeNull PspString string, @CanBeNull TPointer32 endString, int base) { // Assume same as strtol return strtol(string, endString, base); } @HLEFunction(nid = 0xB49A7697, version = 150) public int strncpy(@CanBeNull @BufferInfo(lengthInfo=LengthInfo.nextNextParameter, usage=Usage.out) TPointer destAddr, @CanBeNull @BufferInfo(lengthInfo=LengthInfo.nextParameter, usage=Usage.in) TPointer srcAddr, int size) { int srcLength = AbstractNativeCodeSequence.getStrlen(srcAddr.getAddress()); if (srcLength < size) { destAddr.memcpy(srcAddr.getAddress(), srcLength + 1); destAddr.clear(srcLength + 1, size - srcLength - 1); } else { destAddr.memcpy(srcAddr.getAddress(), size); } return destAddr.getAddress(); } @HLEFunction(nid = 0x7DEE14DE, version = 150) public long __udivdi3(long a, long b) { return a / b; } @HLEFunction(nid = 0x5E8E5F42, version = 150) public long __umoddi3(long a, long b) { return a % b; } }