109 lines
4.4 KiB
Java
109 lines
4.4 KiB
Java
package konogonka.Tools.XCI;
|
|
|
|
import konogonka.RainbowHexDump;
|
|
|
|
import java.io.IOException;
|
|
import java.io.RandomAccessFile;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.util.Arrays;
|
|
import java.util.LinkedList;
|
|
|
|
import static konogonka.LoperConverter.*;
|
|
|
|
/**
|
|
* HFS0
|
|
* */
|
|
public class HFS0Provider {
|
|
|
|
private boolean magicHFS0;
|
|
private int filesCnt;
|
|
private boolean paddingHfs0;
|
|
private int stringTableSize;
|
|
private long rawFileDataStart;
|
|
|
|
private HFS0File[] hfs0Files;
|
|
|
|
HFS0Provider(long hfsOffsetPosition, RandomAccessFile raf) throws Exception{
|
|
byte[] hfs0bytes = new byte[16];
|
|
try{
|
|
raf.seek(hfsOffsetPosition);
|
|
if (raf.read(hfs0bytes) != 16){
|
|
throw new Exception("Read HFS0 structure failure. Can't read first 16 bytes on requested offset.");
|
|
}
|
|
}
|
|
catch (IOException ioe){
|
|
throw new Exception("Read HFS0 structure failure. Can't read first 16 bytes on requested offset: "+ioe.getMessage());
|
|
}
|
|
magicHFS0 = Arrays.equals(Arrays.copyOfRange(hfs0bytes, 0, 4),new byte[]{0x48, 0x46, 0x53, 0x30});
|
|
filesCnt = getLEint(hfs0bytes, 0x4);
|
|
stringTableSize = getLEint(hfs0bytes, 8);
|
|
paddingHfs0 = Arrays.equals(Arrays.copyOfRange(hfs0bytes, 12, 16),new byte[4]);
|
|
|
|
hfs0Files = new HFS0File[filesCnt];
|
|
|
|
// TODO: IF NOT EMPTY TABLE:
|
|
|
|
long[] offsetHfs0files = new long[filesCnt];
|
|
long[] sizeHfs0files = new long[filesCnt];
|
|
int[] hashedRegionSizeHfs0Files = new int[filesCnt];
|
|
boolean[] paddingHfs0Files = new boolean[filesCnt];
|
|
byte[][] SHA256HashHfs0Files = new byte[filesCnt][];
|
|
int[] strTableOffsets = new int[filesCnt];
|
|
|
|
try {
|
|
// Populate meta information regarding each file inside (?) HFS0
|
|
byte[] metaInfoBytes = new byte[64];
|
|
for (int i=0; i < filesCnt; i++){
|
|
if (raf.read(metaInfoBytes) != 64) {
|
|
throw new Exception("Read HFS0 File Entry Table failure for file # "+i);
|
|
}
|
|
offsetHfs0files[i] = getLElong(metaInfoBytes, 0);
|
|
sizeHfs0files[i] = getLElong(metaInfoBytes, 8);
|
|
hashedRegionSizeHfs0Files[i] = getLEint(metaInfoBytes, 20);
|
|
paddingHfs0Files[i] = Arrays.equals(Arrays.copyOfRange(metaInfoBytes, 24, 32), new byte[8]);
|
|
SHA256HashHfs0Files[i] = Arrays.copyOfRange(metaInfoBytes, 32, 64);
|
|
|
|
strTableOffsets[i] = getLEint(metaInfoBytes, 16);
|
|
}
|
|
// Define location of actual data for this HFS0
|
|
rawFileDataStart = raf.getFilePointer()+stringTableSize;
|
|
if (stringTableSize <= 0)
|
|
throw new Exception("String table size of HFS0 less or equal to zero");
|
|
byte[] stringTbl = new byte[stringTableSize];
|
|
if (raf.read(stringTbl) != stringTableSize){
|
|
throw new Exception("Read HFS0 String table failure. Can't read requested string table size ("+stringTableSize+")");
|
|
}
|
|
String[] namesHfs0files = new String[filesCnt];
|
|
// Parse string table
|
|
for (int i=0; i < filesCnt; i++){
|
|
int j = 0;
|
|
while (stringTbl[strTableOffsets[i]+j] != (byte)0x00)
|
|
j++;
|
|
namesHfs0files[i] = new String(stringTbl, strTableOffsets[i], j, StandardCharsets.UTF_8);
|
|
}
|
|
//----------------------------------------------------------------------------------------------------------
|
|
// Set files
|
|
for (int i=0; i < filesCnt; i++){
|
|
hfs0Files[i] = new HFS0File(
|
|
namesHfs0files[i],
|
|
offsetHfs0files[i],
|
|
sizeHfs0files[i],
|
|
hashedRegionSizeHfs0Files[i],
|
|
paddingHfs0Files[i],
|
|
SHA256HashHfs0Files[i]
|
|
);
|
|
}
|
|
}
|
|
catch (IOException ioe){
|
|
throw new Exception("Read HFS0 structure failure: "+ioe.getMessage());
|
|
}
|
|
}
|
|
|
|
public boolean isMagicHFS0() { return magicHFS0; }
|
|
public int getFilesCnt() { return filesCnt; }
|
|
public boolean isPaddingHfs0() { return paddingHfs0; }
|
|
public int getStringTableSize() { return stringTableSize; }
|
|
|
|
public long getRawFileDataStart() { return rawFileDataStart; }
|
|
public HFS0File[] getHfs0Files() { return hfs0Files; }
|
|
} |