/*
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.format;
import static jpcsp.util.Utilities.readStringNZ;
import static jpcsp.util.Utilities.readUByte;
import static jpcsp.util.Utilities.readUHalf;
import static jpcsp.util.Utilities.readWord;
import java.io.IOException;
import java.io.File;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import jpcsp.crypto.CryptoEngine;
import jpcsp.settings.Settings;
/**
*
* @author shadow
*/
@SuppressWarnings("unused")
public class PSP {
public static final int PSP_HEADER_SIZE = 336;
public static final int PSP_MAGIC = 0x5053507E;
private int magic;
private int mod_attr;
private int comp_mod_attr;
private int mod_ver_lo;
private int mod_ver_hi;
private String modname;
private int mod_version;
private int nsegments;
private int elf_size;
private int psp_size;
private int boot_entry;
private int modinfo_offset;
private int bss_size;
private int[] seg_align = new int[4];
private int[] seg_address = new int[4];
private int[] seg_size = new int[4];
private int[] reserved = new int[5];
private int devkit_version;
private int dec_mode;
private int pad;
private int overlap_size;
private int[] aes_key = new int[16];
private int[] cmac_key = new int[16];
private int[] cmac_header_hash = new int[16];
private int comp_size;
private int comp_offset;
private int unk1;
private int unk2;
private int[] cmac_data_hash = new int[16];
private int tag;
private int[] sig_check = new int[88];
private int[] sha1_hash = new int[20];
private int[] key_data = new int[16];
public PSP(ByteBuffer f) throws IOException {
read(f);
}
private void read(ByteBuffer f) throws IOException {
if (f.capacity() == 0) {
return;
}
magic = readWord(f);
mod_attr = readUHalf(f);
comp_mod_attr = readUHalf(f);
mod_ver_lo = readUByte(f);
mod_ver_hi = readUByte(f);
modname = readStringNZ(f, 28);
mod_version = readUByte(f);
nsegments = readUByte(f);
elf_size = readWord(f);
psp_size = readWord(f);
boot_entry = readWord(f);
modinfo_offset = readWord(f);
bss_size = readWord(f);
seg_align[0] = readUHalf(f);
seg_align[1] = readUHalf(f);
seg_align[2] = readUHalf(f);
seg_align[3] = readUHalf(f);
seg_address[0] = readWord(f);
seg_address[1] = readWord(f);
seg_address[2] = readWord(f);
seg_address[3] = readWord(f);
seg_size[0] = readWord(f);
seg_size[1] = readWord(f);
seg_size[2] = readWord(f);
seg_size[3] = readWord(f);
reserved[0] = readWord(f);
reserved[1] = readWord(f);
reserved[2] = readWord(f);
reserved[3] = readWord(f);
reserved[4] = readWord(f);
devkit_version = readWord(f);
dec_mode = readUByte(f);
pad = readUByte(f);
overlap_size = readUHalf(f);
for (int i = 0; i < 16; i++) {
aes_key[i] = readUByte(f);
}
for (int i = 0; i < 16; i++) {
cmac_key[i] = readUByte(f);
}
for (int i = 0; i < 16; i++) {
cmac_header_hash[i] = readUByte(f);
}
comp_size = readWord(f);
comp_offset = readWord(f);
unk1 = readWord(f);
unk2 = readWord(f);
for (int i = 0; i < 16; i++) {
cmac_data_hash[i] = readUByte(f);
}
tag = readWord(f);
for (int i = 0; i < 88; i++) {
sig_check[i] = readUByte(f);
}
for (int i = 0; i < 20; i++) {
sha1_hash[i] = readUByte(f);
}
for (int i = 0; i < 16; i++) {
key_data[i] = readUByte(f);
}
}
public ByteBuffer decrypt(ByteBuffer f) {
if (f.capacity() == 0) {
return null;
}
CryptoEngine crypto = new CryptoEngine();
byte[] inBuf;
if (f.hasArray() && f.position() <= PSP_HEADER_SIZE) {
inBuf = f.array();
} else {
int currentPosition = f.position();
f.position(currentPosition - PSP_HEADER_SIZE);
inBuf = new byte[f.remaining()];
f.get(inBuf);
f.position(currentPosition);
}
int inSize = inBuf.length;
int retsize = crypto.getPRXEngine().DecryptPRX(inBuf, inSize, null, 0, 2, null, null);
if (CryptoEngine.getExtractEbootStatus()) {
try {
String ebootPath = Settings.getInstance().getDiscTmpDirectory();
new File(ebootPath).mkdirs();
RandomAccessFile raf = new RandomAccessFile(ebootPath + "EBOOT.BIN", "rw");
raf.write(inBuf, 0, retsize);
raf.close();
} catch (Exception e) {
// Ignore.
}
}
return ByteBuffer.wrap(inBuf, 0, retsize);
}
public boolean isValid() {
return magic == PSP_MAGIC; // ~PSP
}
public String getModname() {
return modname;
}
}