s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) { std::shared_ptr<vfsFileBase> packed_stream(Emu.GetVFS().OpenFile(packed_file, fom::read)); std::shared_ptr<vfsFileBase> unpacked_stream(Emu.GetVFS().OpenFile(unpacked_file, fom::write | fom::create | fom::trunc)); if (!packed_stream || !packed_stream->IsOpened()) { cellFs.Error("File '%s' not found!", packed_file.c_str()); return CELL_ENOENT; } if (!unpacked_stream || !unpacked_stream->IsOpened()) { cellFs.Error("File '%s' couldn't be created!", unpacked_file.c_str()); return CELL_ENOENT; } char buffer[10200]; packed_stream->Read(buffer, 256); u32 format = *(be_t<u32>*)&buffer[0]; if (format != 0x4E504400) // "NPD\x00" { cellFs.Error("Illegal format. Expected 0x4E504400, but got 0x%08x", format); return CELL_EFSSPECIFIC; } u32 version = *(be_t<u32>*)&buffer[0x04]; u32 flags = *(be_t<u32>*)&buffer[0x80]; u32 blockSize = *(be_t<u32>*)&buffer[0x84]; u64 filesizeOutput = *(be_t<u64>*)&buffer[0x88]; u64 filesizeInput = packed_stream->GetSize(); u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); // SDATA file is compressed if (flags & 0x1) { cellFs.Warning("cellFsSdataOpen: Compressed SDATA files are not supported yet."); return CELL_EFSSPECIFIC; } // SDATA file is NOT compressed else { u32 t1 = (flags & 0x20) ? 0x20 : 0x10; u32 startOffset = (blockCount * t1) + 0x100; u64 filesizeTmp = (filesizeOutput + 0xF) & 0xFFFFFFF0 + startOffset; if (!sdata_check(version, flags, filesizeInput, filesizeTmp)) { cellFs.Error("cellFsSdataOpen: Wrong header information."); return CELL_EFSSPECIFIC; } if (flags & 0x20) packed_stream->Seek(0x100); else packed_stream->Seek(startOffset); for (u32 i = 0; i < blockCount; i++) { if (flags & 0x20) packed_stream->Seek(packed_stream->Tell() + t1); if (!(blockCount - i - 1)) blockSize = (u32)(filesizeOutput - i * blockSize); packed_stream->Read(buffer + 256, blockSize); unpacked_stream->Write(buffer + 256, blockSize); } } return CELL_OK; }
s32 sdata_unpack(const std::string& packed_file, const std::string& unpacked_file) { fs::file packed_stream(vfs::get(packed_file)); fs::file unpacked_stream(vfs::get(unpacked_file), fs::rewrite); if (!packed_stream) { cellFs.error("File '%s' not found!", packed_file); return CELL_ENOENT; } if (!unpacked_stream) { cellFs.error("File '%s' couldn't be created!", unpacked_file); return CELL_ENOENT; } char buffer[10200]; packed_stream.read(buffer, 256); u32 format = *(be_t<u32>*)&buffer[0]; if (format != 0x4E504400) // "NPD\x00" { cellFs.error("Illegal format. Expected 0x4E504400, but got 0x%08x", format); return CELL_EFSSPECIFIC; } u32 version = *(be_t<u32>*)&buffer[0x04]; u32 flags = *(be_t<u32>*)&buffer[0x80]; u32 blockSize = *(be_t<u32>*)&buffer[0x84]; u64 filesizeOutput = *(be_t<u64>*)&buffer[0x88]; u64 filesizeInput = packed_stream.size(); u32 blockCount = (u32)((filesizeOutput + blockSize - 1) / blockSize); // SDATA file is compressed if (flags & 0x1) { cellFs.warning("cellFsSdataOpen: Compressed SDATA files are not supported yet."); return CELL_EFSSPECIFIC; } // SDATA file is NOT compressed else { u32 t1 = (flags & 0x20) ? 0x20 : 0x10; u32 startOffset = (blockCount * t1) + 0x100; u64 filesizeTmp = (filesizeOutput + 0xF) & 0xFFFFFFF0 + startOffset; if (!sdata_check(version, flags, filesizeInput, filesizeTmp)) { cellFs.error("cellFsSdataOpen: Wrong header information."); return CELL_EFSSPECIFIC; } if (flags & 0x20) { packed_stream.seek(0x100); } else { packed_stream.seek(startOffset); } for (u32 i = 0; i < blockCount; i++) { if (flags & 0x20) { packed_stream.seek(t1, fs::seek_cur); } if (!(blockCount - i - 1)) { blockSize = (u32)(filesizeOutput - i * blockSize); } packed_stream.read(buffer + 256, blockSize); unpacked_stream.write(buffer + 256, blockSize); } } return CELL_OK; }