/* Load the contents of an existing TexturePAK */ public override PAKReturnType Load() { if (!File.Exists(FilePathPAK)) { return(PAKReturnType.FAIL_TRIED_TO_LOAD_VIRTUAL_ARCHIVE); } try { /* First, parse the BIN and pull ALL info from it */ BinaryReader ArchiveFileBin = new BinaryReader(File.OpenRead(FilePathBIN)); //Read the header info from the BIN VersionNumber_BIN = ArchiveFileBin.ReadInt32(); if (VersionNumber_BIN != 45) { return(PAKReturnType.FAIL_ARCHIVE_IS_NOT_EXCPETED_TYPE); } //BIN version number is 45 for textures NumberOfEntriesBIN = ArchiveFileBin.ReadInt32(); HeaderListBeginBIN = ArchiveFileBin.ReadInt32(); //Read all file names from BIN string ThisFileName = ""; for (int i = 0; i < NumberOfEntriesBIN; i++) { ThisFileName = ""; for (byte b; (b = ArchiveFileBin.ReadByte()) != 0x00;) { ThisFileName += (char)b; } if (Path.GetExtension(ThisFileName).ToUpper() != ".DDS") { ThisFileName += ".dds"; } //Create texture entry and add filename TEX4 TextureEntry = new TEX4(); TextureEntry.FileName = ThisFileName; TextureEntries.Add(TextureEntry); } //Read the texture headers from the BIN ArchiveFileBin.BaseStream.Position = HeaderListBeginBIN + 12; for (int i = 0; i < NumberOfEntriesBIN; i++) { TextureEntries[i].HeaderPos = (int)ArchiveFileBin.BaseStream.Position; for (int x = 0; x < 4; x++) { TextureEntries[i].Magic += ArchiveFileBin.ReadChar(); } TextureEntries[i].Format = (TextureFormat)ArchiveFileBin.ReadInt32(); TextureEntries[i].Length_V2 = ArchiveFileBin.ReadInt32(); TextureEntries[i].Length_V1 = ArchiveFileBin.ReadInt32(); TextureEntries[i].Texture_V1.Width = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V1.Height = ArchiveFileBin.ReadInt16(); TextureEntries[i].Unk_V1 = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V2.Width = ArchiveFileBin.ReadInt16(); TextureEntries[i].Texture_V2.Height = ArchiveFileBin.ReadInt16(); TextureEntries[i].Unk_V2 = ArchiveFileBin.ReadInt16(); TextureEntries[i].UnknownHeaderBytes = ArchiveFileBin.ReadBytes(20); } /* Second, parse the PAK and pull ONLY header info from it - we'll pull textures when requested (to save memory) */ ArchiveFileBin.Close(); BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); //Read the header info from the PAK BigEndianUtils BigEndian = new BigEndianUtils(); ArchiveFile.BaseStream.Position += 4; //Skip nulls VersionNumber_PAK = BigEndian.ReadInt32(ArchiveFile); if (BigEndian.ReadInt32(ArchiveFile) != VersionNumber_BIN) { throw new Exception("Archive version mismatch!"); } NumberOfEntriesPAK = BigEndian.ReadInt32(ArchiveFile); if (BigEndian.ReadInt32(ArchiveFile) != NumberOfEntriesPAK) { throw new Exception("PAK entry count mismatch!"); } ArchiveFile.BaseStream.Position += 12; //Skip unknowns (1,1,1) //Read the texture headers from the PAK int OffsetTracker = (NumberOfEntriesPAK * 48) + 32; for (int i = 0; i < NumberOfEntriesPAK; i++) { //Header indexes are out of order, so optimise replacements by saving position int HeaderPosition = (int)ArchiveFile.BaseStream.Position; //Pull the entry info byte[] UnknownHeaderLead = ArchiveFile.ReadBytes(8); int PartLength = BigEndian.ReadInt32(ArchiveFile); if (PartLength != BigEndian.ReadInt32(ArchiveFile)) { continue; } byte[] UnknownHeaderTrail_1 = ArchiveFile.ReadBytes(18); //Find the entry TEX4 TextureEntry = TextureEntries[BigEndian.ReadInt16(ArchiveFile)]; TEX4_Part TexturePart = (!TextureEntry.Texture_V1.Saved) ? TextureEntry.Texture_V1 : TextureEntry.Texture_V2; //Write out the info TexturePart.HeaderPos = HeaderPosition; TexturePart.StartPos = OffsetTracker; TexturePart.UnknownHeaderLead = UnknownHeaderLead; TexturePart.Length = PartLength; TexturePart.Saved = true; TexturePart.UnknownHeaderTrail_1 = UnknownHeaderTrail_1; TexturePart.UnknownHeaderTrail_2 = ArchiveFile.ReadBytes(12); //Keep file offset updated OffsetTracker += TexturePart.Length; } HeaderListEndPAK = (int)ArchiveFile.BaseStream.Position; //Close PAK ArchiveFile.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
/* Load the contents of an existing ModelPAK */ public override PAKReturnType Load() { if (!File.Exists(FilePathPAK)) { return(PAKReturnType.FAIL_TRIED_TO_LOAD_VIRTUAL_ARCHIVE); } /* TODO: Verify the PAK loading is a ModelPAK by BIN version number */ try { //First, parse the MTL file to find material info string PathToMTL = FilePathPAK.Substring(0, FilePathPAK.Length - 3) + "MTL"; BinaryReader ArchiveFileMtl = new BinaryReader(File.OpenRead(PathToMTL)); //Header ArchiveFileMtl.BaseStream.Position += 40; //There are some knowns here, just not required for us yet int MaterialEntryCount = ArchiveFileMtl.ReadInt16(); ArchiveFileMtl.BaseStream.Position += 2; //Skip unknown //Strings - more work will be done on materials eventually, //but taking their names for now is good enough for model export List <string> MaterialEntries = new List <string>(); string ThisMaterialString = ""; for (int i = 0; i < MaterialEntryCount; i++) { while (true) { byte ThisByte = ArchiveFileMtl.ReadByte(); if (ThisByte == 0x00) { MaterialEntries.Add(ThisMaterialString); ThisMaterialString = ""; break; } ThisMaterialString += (char)ThisByte; } } ArchiveFileMtl.Close(); //Read the header info from BIN BinaryReader ArchiveFileBin = new BinaryReader(File.OpenRead(FilePathBIN)); ArchiveFileBin.BaseStream.Position += 4; //Skip magic TableCountPt2 = ArchiveFileBin.ReadInt32(); ArchiveFileBin.BaseStream.Position += 4; //Skip unknown TableCountPt1 = ArchiveFileBin.ReadInt32(); //Skip past table 1 for (int i = 0; i < TableCountPt1; i++) { byte ThisByte = 0x00; while (ThisByte != 0xFF) { ThisByte = ArchiveFileBin.ReadByte(); } } ArchiveFileBin.BaseStream.Position += 23; //Read file list info FilenameListEnd = ArchiveFileBin.ReadInt32(); int FilenameListStart = (int)ArchiveFileBin.BaseStream.Position; //Read all file names (bytes) byte[] filename_bytes = ArchiveFileBin.ReadBytes(FilenameListEnd); //Read table 2 (skipping all unknowns for now) ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); for (int i = 0; i < TableCountPt2; i++) { CS2 new_entry = new CS2(); new_entry.FilenameOffset = ArchiveFileBin.ReadInt32(); new_entry.Filename = BinaryUtils.GetStringFromByteArray(filename_bytes, new_entry.FilenameOffset); ArchiveFileBin.BaseStream.Position += 4; new_entry.ModelPartNameOffset = ArchiveFileBin.ReadInt32(); new_entry.ModelPartName = BinaryUtils.GetStringFromByteArray(filename_bytes, new_entry.ModelPartNameOffset); ArchiveFileBin.BaseStream.Position += 44; new_entry.MaterialLibaryIndex = ArchiveFileBin.ReadInt32(); new_entry.MaterialName = MaterialEntries[new_entry.MaterialLibaryIndex]; ArchiveFileBin.BaseStream.Position += 8; new_entry.BlockSize = ArchiveFileBin.ReadInt32(); ArchiveFileBin.BaseStream.Position += 14; new_entry.ScaleFactor = ArchiveFileBin.ReadInt16(); //Maybe? ArchiveFileBin.BaseStream.Position += 2; new_entry.VertCount = ArchiveFileBin.ReadInt16(); new_entry.FaceCount = ArchiveFileBin.ReadInt16(); new_entry.BoneCount = ArchiveFileBin.ReadInt16(); ModelEntries.Add(new_entry); } ArchiveFileBin.Close(); //Get extra info from each header in the PAK BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); BigEndianUtils BigEndian = new BigEndianUtils(); ArchiveFile.BaseStream.Position += 32; //Skip header for (int i = 0; i < TableCountPt2; i++) { ArchiveFile.BaseStream.Position += 8; //Skip unknowns int ThisPakSize = BigEndian.ReadInt32(ArchiveFile); if (ThisPakSize != BigEndian.ReadInt32(ArchiveFile)) { //Dud entry... handle this somehow? } int ThisPakOffset = BigEndian.ReadInt32(ArchiveFile); ArchiveFile.BaseStream.Position += 14; int ThisIndex = BigEndian.ReadInt16(ArchiveFile); ArchiveFile.BaseStream.Position += 12; if (ThisIndex == -1) { continue; //Again, dud entry. Need to look into this! } //Push it into the correct entry ModelEntries[ThisIndex].PakSize = ThisPakSize; ModelEntries[ThisIndex].PakOffset = ThisPakOffset; } HeaderListEnd = (int)ArchiveFile.BaseStream.Position; //Done! ArchiveFile.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }