s32 cellFsSdataOpen(vm::cptr<char> path, s32 flags, vm::ptr<u32> fd, vm::cptr<void> arg, u64 size) { cellFs.notice("cellFsSdataOpen(path=*0x%x, flags=%#o, fd=*0x%x, arg=*0x%x, size=0x%llx)", path, flags, fd, arg, size); if (flags != CELL_FS_O_RDONLY) { return CELL_EINVAL; } return cellFsOpen(path, CELL_FS_O_RDONLY, fd, vm::make_var<be_t<u32>[2]>({ 0x180, 0x10 }), 8); // Don't implement sdata decryption in this function, it should be done in sys_fs_open() syscall or somewhere else /* std::string suffix = path.substr(path.length() - 5, 5); if (suffix != ".sdat" && suffix != ".SDAT") return CELL_ENOTSDATA; std::string::size_type last_slash = path.rfind('/'); //TODO: use a filesystem library to solve this more robustly last_slash = last_slash == std::string::npos ? 0 : last_slash+1; std::string unpacked_path = "/dev_hdd1/"+path.substr(last_slash,path.length()-last_slash)+".unpacked"; s32 ret = sdata_unpack(path, unpacked_path); if (ret) return ret; fd = idm::GetNewID(Emu.GetVFS().OpenFile(unpacked_path, vfsRead), TYPE_FS_FILE); return CELL_OK; */ }
error_code sys_tty_write(s32 ch, vm::cptr<char> buf, u32 len, vm::ptr<u32> pwritelen) { sys_tty.notice("sys_tty_write(ch=%d, buf=*0x%x, len=%d, pwritelen=*0x%x)", ch, buf, len, pwritelen); if (ch > 15) { return CELL_EINVAL; } if (static_cast<s32>(len) <= 0) { *pwritelen = 0; return CELL_OK; } if (g_tty) { g_tty.write(buf.get_ptr(), len); } *pwritelen = len; return CELL_OK; }
error_code cellPadEnd() { sys_io.notice("cellPadEnd()"); if (!fxm::remove<pad_thread>()) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; }
error_code cellKbEnd() { sys_io.notice("cellKbEnd()"); if (!fxm::remove<KeyboardHandlerBase>()) return CELL_KB_ERROR_UNINITIALIZED; return CELL_OK; }
s32 cellPadEnd() { sys_io.notice("cellPadEnd()"); if (!fxm::remove<PadHandlerBase>()) return CELL_PAD_ERROR_UNINITIALIZED; return CELL_OK; }
s32 cellMouseEnd() { sys_io.notice("cellMouseEnd()"); if (!fxm::remove<MouseHandlerBase>()) { return CELL_MOUSE_ERROR_UNINITIALIZED; } return CELL_OK; }
error_code sys_fs_rename(vm::cptr<char> from, vm::cptr<char> to) { sys_fs.warning("sys_fs_rename(from=%s, to=%s)", from, to); if (!fs::rename(vfs::get(from.get_ptr()), vfs::get(to.get_ptr()))) { return CELL_ENOENT; // ??? } sys_fs.notice("sys_fs_rename(): %s renamed to %s", from, to); return CELL_OK; }
error_code sys_fs_unlink(vm::cptr<char> path) { sys_fs.warning("sys_fs_unlink(path=%s)", path); if (!fs::remove_file(vfs::get(path.get_ptr()))) { switch (auto error = fs::g_tls_error) { case fs::error::noent: return CELL_ENOENT; default: sys_fs.error("sys_fs_unlink(): unknown error %s", error); } return CELL_EIO; // ??? } sys_fs.notice("sys_fs_unlink(): file %s deleted", path); return CELL_OK; }
s32 cellFontRenderCharGlyphImage(vm::ptr<CellFont> font, u32 code, vm::ptr<CellFontRenderSurface> surface, float x, float y, vm::ptr<CellFontGlyphMetrics> metrics, vm::ptr<CellFontImageTransInfo> transInfo) { cellFont.notice("cellFontRenderCharGlyphImage(font=*0x%x, code=0x%x, surface=*0x%x, x=%f, y=%f, metrics=*0x%x, trans=*0x%x)", font, code, surface, x, y, metrics, transInfo); if (!font->renderer_addr) { return CELL_FONT_ERROR_RENDERER_UNBIND; } // Render the character s32 width, height, xoff, yoff; float scale = stbtt_ScaleForPixelHeight(font->stbfont, font->scale_y); unsigned char* box = stbtt_GetCodepointBitmap(font->stbfont, scale, scale, code, &width, &height, &xoff, &yoff); if (!box) { return CELL_OK; } // Get the baseLineY value s32 baseLineY; s32 ascent, descent, lineGap; stbtt_GetFontVMetrics(font->stbfont, &ascent, &descent, &lineGap); baseLineY = (int)((float)ascent * scale); // ??? // Move the rendered character to the surface unsigned char* buffer = vm::_ptr<unsigned char>(surface->buffer.addr()); for (u32 ypos = 0; ypos < (u32)height; ypos++) { if ((u32)y + ypos + yoff + baseLineY >= (u32)surface->height) break; for (u32 xpos = 0; xpos < (u32)width; xpos++) { if ((u32)x + xpos >= (u32)surface->width) break; // TODO: There are some oddities in the position of the character in the final buffer buffer[((s32)y + ypos + yoff + baseLineY)*surface->width + (s32)x + xpos] = box[ypos * width + xpos]; } } stbtt_FreeBitmap(box, 0); return CELL_OK; }
error_code sys_fs_mkdir(vm::cptr<char> path, s32 mode) { sys_fs.warning("sys_fs_mkdir(path=%s, mode=%#o)", path, mode); const std::string& local_path = vfs::get(path.get_ptr()); if (fs::is_dir(local_path)) { return CELL_EEXIST; } if (!fs::create_path(local_path)) { return CELL_EIO; // ??? } sys_fs.notice("sys_fs_mkdir(): directory %s created", path); return CELL_OK; }
error_code sys_fs_opendir(vm::cptr<char> path, vm::ptr<u32> fd) { sys_fs.warning("sys_fs_opendir(path=%s, fd=*0x%x)", path, fd); const std::string& local_path = vfs::get(path.get_ptr()); if (local_path.empty()) { sys_fs.error("sys_fs_opendir(%s) failed: device not mounted", path); return CELL_ENOTMOUNTED; } // TODO: other checks for path if (fs::is_file(local_path)) { sys_fs.error("sys_fs_opendir(%s) failed: path is a file", path); return CELL_ENOTDIR; } fs::dir dir(local_path); if (!dir) { sys_fs.error("sys_fs_opendir(%s): failed to open directory", path); return CELL_ENOENT; } const auto _dir = idm::make_ptr<lv2_dir>(path.get_ptr(), std::move(dir)); if (!_dir) { // out of file descriptors return CELL_EMFILE; } *fd = _dir->id; sys_fs.notice("sys_fs_opendir(%s) -> lv2_fs_id %d", path, _dir->id); return CELL_OK; }