private static Dictionary <string, bool> IsPIFFUser; //if a piff is User, all other piffs for that file are ignored. public static void Init(string basePath) { PIFFsByName = new Dictionary <string, List <IffFile> >(); IsPIFFUser = new Dictionary <string, bool>(); //Directory.CreateDirectory(basePath); if (Directory.Exists("Content/Patch")) { string[] paths = Directory.GetFiles(basePath, "*.piff", SearchOption.AllDirectories); for (int i = 0; i < paths.Length; i++) { string entry = paths[i].Replace('\\', '/'); bool user = entry.Contains("User/"); string filename = Path.GetFileName(entry); IffFile piffFile = new IffFile(entry); PIFF piff = piffFile.List <PIFF>()[0]; if (IsPIFFUser.ContainsKey(piff.SourceIff)) { var old = IsPIFFUser[piff.SourceIff]; if (old != user) { if (user) { //remove old piffs, as they have been overwritten by this user piff. PIFFsByName[piff.SourceIff].Clear(); IsPIFFUser[piff.SourceIff] = true; } else { continue; //a user piff exists. ignore these ones. } } } else { IsPIFFUser.Add(piff.SourceIff, user); } if (!PIFFsByName.ContainsKey(piff.SourceIff)) { PIFFsByName.Add(piff.SourceIff, new List <IffFile>()); } PIFFsByName[piff.SourceIff].Add(piffFile); } } }
public void Patch(IffFile piffFile) { if (RuntimeInfo.State == IffRuntimeState.ReadOnly) { RuntimeInfo.State = IffRuntimeState.PIFFPatch; } var piff = piffFile.List <PIFF>()[0]; //patch existing chunks using the PIFF chunk //also delete chunks marked for deletion var moveChunks = new List <IffChunk>(); var newIDs = new List <ushort>(); foreach (var e in piff.Entries) { var type = CHUNK_TYPES[e.Type]; Dictionary <ushort, object> chunks = null; ByChunkId.TryGetValue(type, out chunks); if (chunks == null) { continue; } object objC = null; chunks.TryGetValue(e.ChunkID, out objC); if (objC == null) { continue; } var chunk = (IffChunk)objC; if (e.Delete) { FullRemoveChunk(chunk); //removed by PIFF } else { chunk.ChunkData = e.Apply(chunk.ChunkData); if (e.ChunkLabel != "") { chunk.ChunkLabel = e.ChunkLabel; } chunk.RuntimeInfo = ChunkRuntimeState.Patched; if (e.ChunkID != e.NewChunkID) { moveChunks.Add(chunk); newIDs.Add(e.NewChunkID); } } } for (int i = 0; i < moveChunks.Count; i++) { MoveAndSwap(moveChunks[i], newIDs[i]); } //add chunks present in the piff to the original file foreach (var typeG in piffFile.ByChunkType) { if (typeG.Key == typeof(PIFF)) { continue; } foreach (var res in typeG.Value) { var chunk = (IffChunk)res; chunk.AddedByPatch = true; if (!ByChunkId.ContainsKey(chunk.GetType()) || !ByChunkId[chunk.GetType()].ContainsKey(chunk.ChunkID)) { this.AddChunk(chunk); } } } }
public static void Init(string basePath) { if (!Directory.Exists(basePath)) { return; } string[] paths = Directory.GetFiles(basePath, "*.piff", SearchOption.AllDirectories); for (int i = 0; i < paths.Length; i++) { string entry = paths[i].Replace('\\', '/'); bool user = entry.Contains("User/"); string filename = Path.GetFileName(entry); PIFF piff; IffFile piffFile; try { piffFile = new IffFile(entry); piff = piffFile.List <PIFF>()[0]; } catch (Exception) { continue; } if (IsPIFFUser.ContainsKey(piff.SourceIff)) { var old = IsPIFFUser[piff.SourceIff]; if (old != user) { if (user) { //remove old piffs, as they have been overwritten by this user piff. PIFFsByName[piff.SourceIff].Clear(); IsPIFFUser[piff.SourceIff] = true; } else { continue; //a user piff exists. ignore these ones. } } } else { IsPIFFUser.Add(piff.SourceIff, user); } if (!PIFFsByName.ContainsKey(piff.SourceIff)) { PIFFsByName.Add(piff.SourceIff, new List <IffFile>()); } PIFFsByName[piff.SourceIff].Add(piffFile); } string[] otfs = Directory.GetFiles(basePath, "*.otf", SearchOption.AllDirectories); foreach (var otf in otfs) { string entry = otf.Replace('\\', '/'); OtfRewrite[Path.GetFileName(entry)] = entry; } foreach (var piffs in PIFFsByName) { foreach (var piff in piffs.Value) { var addedOBJD = piff.List <OBJD>(); if (addedOBJD != null) { OBJDAdded.Add(piffs.Key); continue; } var pChunk = piff.List <PIFF>()?.FirstOrDefault(); if (pChunk != null && pChunk.Entries.Any(x => x.Type == "OBJD")) { OBJDAdded.Add(piffs.Key); continue; } } } }
/// <summary> /// Attempts to write this chunk to a stream (presumably an IFF or PIFF) /// </summary> /// <param name="iff"></param> /// <param name="stream"></param> /// <returns>True if data has been written, false if not. </returns> public virtual bool Write(IffFile iff, Stream stream) { return(false); }
/// <summary> /// Reads this chunk from an IFF. /// </summary> /// <param name="iff">The IFF to read from.</param> /// <param name="stream">The stream to read from.</param> public abstract void Read(IffFile iff, Stream stream);
public static IffFile GeneratePiff(IFF.IffFile iff, HashSet<Type> allowedTypes, HashSet<Type> disallowedTypes) { var piffFile = new IFF.IffFile(); var piff = new IFF.Chunks.PIFF(); piff.SourceIff = iff.Filename; var entries = new List<PIFFEntry>(); var chunks = iff.ListAll(); //write removals first foreach (var c in iff.RemovedOriginal) { lock (c) { if ((allowedTypes == null || allowedTypes.Contains(c.GetType())) && (disallowedTypes == null || !disallowedTypes.Contains(c.GetType()))) { entries.Add(new PIFFEntry { Type = c.ChunkType, ChunkID = c.OriginalID, Delete = true, ChunkLabel = c.ChunkLabel, ChunkFlags = c.ChunkFlags }); } } } foreach (var c in chunks) { lock (c) { if ((allowedTypes == null || allowedTypes.Contains(c.GetType())) && (disallowedTypes == null || !disallowedTypes.Contains(c.GetType()))) { if (c.AddedByPatch) { //this chunk has been newly added. var oldParent = c.ChunkParent; piffFile.AddChunk(c); c.ChunkParent = oldParent; } else if ((c.RuntimeInfo == ChunkRuntimeState.Modified || c.RuntimeInfo == ChunkRuntimeState.Patched)) { var chunkD = MakeChunkDiff(c); if (chunkD != null && (chunkD.Patches.Length > 0 || c.OriginalLabel != c.ChunkLabel || c.OriginalID != c.ChunkID)) { entries.Add(chunkD); } c.RuntimeInfo = ChunkRuntimeState.Patched; } } } } if (entries.Count == 0) return null; //no patch data... piff.Entries = entries.ToArray(); piff.ChunkID = 256; piff.ChunkLabel = (piff.SourceIff + " patch"); piff.ChunkProcessed = true; piffFile.AddChunk(piff); piffFile.Filename = piff.SourceIff.Substring(0, piff.SourceIff.Length - 4)+".piff"; return piffFile; }