/* Save out our material mappings archive */ public override PAKReturnType Save() { try { //Re-write out to the PAK ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); BinaryWriter ArchiveWriter = new BinaryWriter(File.OpenWrite(FilePathPAK)); ArchiveWriter.BaseStream.SetLength(0); ArchiveWriter.Write(FileHeaderJunk); ArchiveWriter.Write(MaterialMappingEntries.Count); foreach (EntryMaterialMappingsPAK ThisMatRemap in MaterialMappingEntries) { ArchiveWriter.Write(ThisMatRemap.MapHeader); ArchiveWriter.Write(ThisMatRemap.MapEntryCoupleCount); ArchiveWriter.Write(ThisMatRemap.MapJunk); ArchiveWriter.Write(ThisMatRemap.MapFilename.Length); BinaryUtils.WriteString(ThisMatRemap.MapFilename, ArchiveWriter); foreach (string MaterialName in ThisMatRemap.MapMatEntries) { ArchiveWriter.Write(MaterialName.Length); BinaryUtils.WriteString(MaterialName, ArchiveWriter); } } ArchiveWriter.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
/* Replace an existing file in the TexturePAK archive */ public override PAKReturnType ReplaceFile(string PathToNewFile, string FileName) { try { //Get the texture entry & parse new DDS int EntryIndex = GetFileIndex(FileName); if (EntryIndex == -1) { return(PAKReturnType.FAIL_GENERAL_LOGIC_ERROR); //CHANGED FOR OPENCAGE } TEX4 TextureEntry = TextureEntries[EntryIndex]; DDSReader NewTexture = new DDSReader(PathToNewFile); //Currently we only apply the new texture to the "biggest", some have lower mips that we don't edit (TODO) TEX4_Part BiggestPart = TextureEntry.Texture_V2; if (BiggestPart.HeaderPos == -1 || !BiggestPart.Saved) { BiggestPart = TextureEntry.Texture_V1; } if (BiggestPart.HeaderPos == -1 || !BiggestPart.Saved) { return(PAKReturnType.FAIL_REQUEST_IS_UNSUPPORTED); //Shouldn't reach this. } //CATHODE seems to ignore texture header information regarding size, so as default, resize any imported textures to the original size. //An option is provided in the toolkit to write size information to the header (done above) however, so don't resize if that's the case. //More work needs to be done to figure out why CATHODE doesn't honour the header's size value. int OriginalLength = BiggestPart.Length; Array.Resize(ref NewTexture.DataBlock, OriginalLength); //Update our internal knowledge of the textures BiggestPart.Length = (int)NewTexture.DataBlock.Length; BiggestPart.Width = (Int16)NewTexture.Width; BiggestPart.Height = (Int16)NewTexture.Height; TextureEntry.Format = NewTexture.Format; //TODO: Update smallest here too if it exists! //Will need to be written into the PAK at "Pull PAK sections before/after V2" too - headers are handled already. //Load the BIN and write out updated BIN texture header BinaryWriter ArchiveFileBinWriter = new BinaryWriter(File.OpenWrite(FilePathBIN)); ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); ArchiveFileBinWriter.BaseStream.Position = TextureEntry.HeaderPos; BinaryUtils.WriteString(TextureEntry.Magic, ArchiveFileBinWriter); ArchiveFileBinWriter.Write(BitConverter.GetBytes((int)TextureEntry.Format)); ArchiveFileBinWriter.Write((TextureEntry.Texture_V2.Length == -1) ? 0 : TextureEntry.Texture_V2.Length); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Length); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Width); ArchiveFileBinWriter.Write(TextureEntry.Texture_V1.Height); ArchiveFileBinWriter.Write(TextureEntry.Unk_V1); ArchiveFileBinWriter.Write(TextureEntry.Texture_V2.Width); ArchiveFileBinWriter.Write(TextureEntry.Texture_V2.Height); ArchiveFileBinWriter.Write(TextureEntry.Unk_V2); ArchiveFileBinWriter.Write(TextureEntry.UnknownHeaderBytes); ArchiveFileBinWriter.Close(); //Update headers for V1+2 in PAK if they exist BinaryWriter ArchiveFileWriter = new BinaryWriter(File.OpenWrite(FilePathPAK)); BigEndianUtils BigEndian = new BigEndianUtils(); if (TextureEntry.Texture_V1.HeaderPos != -1) { ArchiveFileWriter.BaseStream.Position = TextureEntry.Texture_V1.HeaderPos; ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderLead); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V1.Length))); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V1.Length))); ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderTrail_1); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes((Int16)EntryIndex))); ArchiveFileWriter.Write(TextureEntry.Texture_V1.UnknownHeaderTrail_2); } if (TextureEntry.Texture_V2.HeaderPos != -1) { ArchiveFileWriter.BaseStream.Position = TextureEntry.Texture_V2.HeaderPos; ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderLead); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V2.Length))); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes(TextureEntry.Texture_V2.Length))); ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderTrail_1); ArchiveFileWriter.Write(BigEndian.FlipEndian(BitConverter.GetBytes((Int16)EntryIndex))); ArchiveFileWriter.Write(TextureEntry.Texture_V2.UnknownHeaderTrail_2); } ArchiveFileWriter.Close(); //Pull PAK sections before/after V2 BinaryReader ArchiveFile = new BinaryReader(File.OpenRead(FilePathPAK)); byte[] PAK_Pt1 = ArchiveFile.ReadBytes(BiggestPart.StartPos); ArchiveFile.BaseStream.Position += OriginalLength; byte[] PAK_Pt2 = ArchiveFile.ReadBytes((int)ArchiveFile.BaseStream.Length - (int)ArchiveFile.BaseStream.Position); ArchiveFile.Close(); //Write the PAK back out with new content ArchiveFileWriter = new BinaryWriter(File.OpenWrite(FilePathPAK)); ArchiveFileWriter.BaseStream.SetLength(0); ArchiveFileWriter.Write(PAK_Pt1); ArchiveFileWriter.Write(NewTexture.DataBlock); ArchiveFileWriter.Write(PAK_Pt2); ArchiveFileWriter.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }
/* Save out our PAK2 archive */ public override PAKReturnType Save() { try { //Open/create PAK2 for writing BinaryWriter ArchiveFileWrite; if (File.Exists(FilePathPAK)) { ArchiveFileWrite = new BinaryWriter(File.OpenWrite(FilePathPAK)); ArchiveFileWrite.BaseStream.SetLength(0); } else { ArchiveFileWrite = new BinaryWriter(File.Create(FilePathPAK)); } ExtraBinaryUtils BinaryUtils = new ExtraBinaryUtils(); //Write header BinaryUtils.WriteString("PAK2", ArchiveFileWrite); int OffsetListBegin_New = 0; for (int i = 0; i < Pak2Files.Count; i++) { OffsetListBegin_New += Pak2Files[i].Filename.Length + 1; } ArchiveFileWrite.Write(OffsetListBegin_New); ArchiveFileWrite.Write(Pak2Files.Count); ArchiveFileWrite.Write(4); //Write filenames for (int i = 0; i < Pak2Files.Count; i++) { BinaryUtils.WriteString(Pak2Files[i].Filename.Replace("\\", "/"), ArchiveFileWrite); ArchiveFileWrite.Write((byte)0x00); } //Write placeholder offsets for now, we'll correct them after writing the content OffsetListBegin = (int)ArchiveFileWrite.BaseStream.Position; for (int i = 0; i < Pak2Files.Count; i++) { ArchiveFileWrite.Write(0); } //Write files for (int i = 0; i < Pak2Files.Count; i++) { while (ArchiveFileWrite.BaseStream.Position % 4 != 0) { ArchiveFileWrite.Write((byte)0x00); } ArchiveFileWrite.Write(Pak2Files[i].Content); Pak2Files[i].Offset = (int)ArchiveFileWrite.BaseStream.Position; } //Re-write offsets with correct values ArchiveFileWrite.BaseStream.Position = OffsetListBegin; for (int i = 0; i < Pak2Files.Count; i++) { ArchiveFileWrite.Write(Pak2Files[i].Offset); } ArchiveFileWrite.Close(); return(PAKReturnType.SUCCESS); } catch (IOException) { return(PAKReturnType.FAIL_COULD_NOT_ACCESS_FILE); } catch (Exception) { return(PAKReturnType.FAIL_UNKNOWN); } }