/*
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 jpcsp.util.ByteUtil;
import jpcsp.util.FileUtil;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import static jpcsp.util.Utilities.formatString;
import static jpcsp.util.Utilities.readUWord;
public class PBP {
public static final int PBP_MAGIC = 0x50425000;
private static final String PBP_UNPACK_PATH_PREFIX = "unpacked-pbp/";
static private final String[] FILE_NAMES = new String[]{
"param.sfo",
"icon0.png",
"icon1.pmf",
"pic0.png",
"pic1.png",
"snd0.at3",
"psp.data",
"psar.data",
};
static private final int TOTAL_FILES = 8;
static private final int PARAM_SFO = 0;
static private final int ICON0_PNG = 1;
static private final int ICON1_PMF = 2;
static private final int PIC0_PNG = 3;
static private final int PIC1_PNG = 4;
static private final int SND0_AT3 = 5;
static private final int PSP_DATA = 6;
static private final int PSAR_DATA = 7;
private String info;
private int size_pbp;
private int p_magic;
private int p_version;
private int[] p_offsets;
private Elf32 elf32;
private PSF psf;
public boolean isValid() {
return size_pbp != 0 && p_magic == PBP_MAGIC;
}
public void setElf32(Elf32 elf) {
elf32 = elf;
}
public Elf32 getElf32() {
return elf32;
}
public PSF getPSF() {
return psf;
}
public void setInfo(String msg) {
info = msg;
}
public String getInfo() {
return info;
}
public PBP(ByteBuffer f) throws IOException {
size_pbp = f.limit();
if (size_pbp == 0) {
return;
}
p_magic = readUWord(f);
if (isValid()) {
p_version = readUWord(f);
p_offsets = new int[] {readUWord(f),readUWord(f),readUWord(f),readUWord(f),readUWord(f),readUWord(f),readUWord(f),readUWord(f),size_pbp};
info = toString();
}
}
public PSF readPSF(ByteBuffer f) throws IOException {
if (getOffsetParam() > 0) {
f.position(getOffsetParam());
psf = new PSF(getOffsetParam());
psf.read(f);
return psf;
}
return null;
}
@Override
public String toString() {
StringBuilder str = new StringBuilder();
str.append("-----PBP HEADER---------" + "\n");
str.append("p_magic " + "\t\t" + formatString("long", Long.toHexString(p_magic & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_version " + "\t\t" + formatString("long", Long.toHexString(p_version & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_param_sfo " + "\t" + formatString("long", Long.toHexString(getOffsetParam() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_icon0_png " + "\t" + formatString("long", Long.toHexString(getOffsetIcon0() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_icon1_pmf " + "\t" + formatString("long", Long.toHexString(getOffsetIcon1() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_pic0_png " + "\t" + formatString("long", Long.toHexString(getOffsetPic0() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_pic1_png " + "\t" + formatString("long", Long.toHexString(getOffsetPic1() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_snd0_at3 " + "\t" + formatString("long", Long.toHexString(getOffsetSnd0() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_psp_data " + "\t" + formatString("long", Long.toHexString(getOffsetPspData() & 0xFFFFFFFFL).toUpperCase()) + "\n");
str.append("p_offset_psar_data " + "\t" + formatString("long", Long.toHexString(getOffsetPsarData() & 0xFFFFFFFFL).toUpperCase()) + "\n");
return str.toString();
}
private String getName(int index) {
return FILE_NAMES[index];
}
private int getOffset(int index) {
return this.p_offsets[index];
}
private int getSize(int index) {
return this.p_offsets[index + 1] - this.p_offsets[index];
}
private byte[] getBytes(ByteBuffer f, int index) {
return ByteUtil.readBytes(f, getOffset(index), getSize(index));
}
public int getMagic() {
return p_magic;
}
public int getVersion() {
return p_version;
}
public int getOffsetParam() {
return getOffset(PARAM_SFO);
}
public int getOffsetIcon0() {
return getOffset(ICON0_PNG);
}
public int getOffsetIcon1() {
return getOffset(ICON1_PMF);
}
public int getOffsetPic0() {
return getOffset(PIC0_PNG);
}
public int getOffsetPic1() {
return getOffset(PIC1_PNG);
}
public int getOffsetSnd0() {
return getOffset(SND0_AT3);
}
public int getOffsetPspData() {
return getOffset(PSP_DATA);
}
public int getOffsetPsarData() {
return getOffset(PSAR_DATA);
}
public int getSizeIcon0() {
return getSize(ICON0_PNG);
}
public static boolean deleteDir(File dir) {
if (dir.isDirectory()) {
String[] children = dir.list();
for (int i = 0; i < children.length; i++) {
boolean success = deleteDir(new File(dir, children[i]));
if (!success) {
return false;
}
}
}
// The directory is now empty so delete it
return dir.delete();
}
public static void unpackPBP(ByteBuffer f) throws IOException {
f.position(0);//seek to 0
PBP pbp = new PBP(f);
if (!pbp.isValid()) {
return;
}
File dir = new File(PBP_UNPACK_PATH_PREFIX);
deleteDir(dir);//delete all files and directory
dir.mkdir();
for (int index = 0; index < TOTAL_FILES; index++) {
FileUtil.writeBytes(new File(PBP_UNPACK_PATH_PREFIX + pbp.getName(index)), pbp.getBytes(f, index));
}
}
}