/// <summary> /// Gets the number of files contained in the specifed ERF file. /// </summary> /// <param name="fileName">The name of the file</param> /// <returns>The number of files in the ERF</returns> public static int GetFileCount(string fileName) { using (FileStream reader = new FileStream(fileName, FileMode.Open)) { // Read the header from the ERF and return the number of files. ErfHeader header = new ErfHeader(reader); return header.EntryCount; } }
/// <summary> /// Saves the ERF file under the specified name. /// </summary> /// <param name="fileName">The name of the file.</param> public void SaveAs(string fileName) { NWNLogger.Log(0, "module.SaveAs entering [{0}]", fileName); // The ERF must be decompressed first unless it is a new ERF. if (keys.Length > 0 && string.Empty == decompressedPath) throw new NWNException("ERF must be decompressed to recreate"); // Copy all of the modified files into the temp directory StringCollection replacedFiles = ReplacedFiles; NWNLogger.Log(0, "module.SaveAs copying {0} modified files into temp directory", replacedFiles.Count); foreach (string file in replacedFiles) File.Copy(file, Path.Combine(decompressedPath, Path.GetFileName(file)), true); // Figure out the new number of files in the ERF and create new // key/resource arrays of the proper size. int fileCount = keys.Length + addedFileHash.Count - removedFiles.Count; NWNLogger.Log(0, "module.SaveAs {0} total files, allocating key/resource arrays", fileCount); ErfKey[] newKeys = new ErfKey[fileCount]; ErfResource[] newResources = new ErfResource[fileCount]; // Create a buffer to store the data. NWNLogger.Log(0, "module.SaveAs creating memory stream"); MemoryStream buffer = new MemoryStream(); // Copy all of the existing not-removed files into the new key/resource // arrays. int index = 0; for (int i = 0; i < keys.Length; i++) { string file = keys[i].FileName; if (string.Empty == file || removedFiles.Contains(file)) continue; // Copy the key/resource pair over. NWNLogger.Log(1, "module.SaveAs copying file[{0}] '{1}'", i, file); newKeys[index] = keys[i]; newResources[index] = resources[i]; // Read the file into the buffer. ReadFileIntoStream(Path.Combine(decompressedPath, file), ref newResources[index], buffer); index++; } // Add all of the new files to the key/resource arrays. StringCollection addedFiles = AddedFiles; foreach (string file in addedFiles) { NWNLogger.Log(1, "module.SaveAs adding new file '{0}'", file); // SBH - depends on mode (NWN1 uses 1.0, 2 uses 1.1) if (NWNInfo.ModeNWN1) newKeys[index] = new ErfKey(file, 1.0); else newKeys[index] = new ErfKey(file, 1.1); newResources[index] = new ErfResource(); // Read the file into the buffer. ReadFileIntoStream(file, ref newResources[index], buffer); index++; } // Figure out how big our descriptions are going to be. NWNLogger.Log(0, "module.SaveAs calcing description size"); int descriptionsCount = 0; for (int i = 0; i < descriptions.Length; i++) descriptionsCount += descriptions[i].SizeInStream; // Create a new resource header and calculate the new offsets. NWNLogger.Log(0, "module.SaveAs creating header"); ErfHeader newHeader = header; newHeader.OffsetToLocalizedString = Marshal.SizeOf(typeof(ErfHeader)); newHeader.OffsetToKeyList = newHeader.OffsetToLocalizedString + descriptionsCount; newHeader.EntryCount = fileCount; //SBH - depends on mode if (NWNInfo.ModeNWN1) newHeader.OffsetToResourceList = newHeader.OffsetToKeyList + (fileCount * ErfKey.SizeOf(1.0)); else newHeader.OffsetToResourceList = newHeader.OffsetToKeyList + (fileCount * ErfKey.SizeOf(1.1)); // Calculate the offset to the beginning of the resource data and adjust // the offsets in the resource array to take this into account. NWNLogger.Log(0, "module.SaveAs calcing offsets"); int offsetToData = newHeader.OffsetToResourceList + (fileCount * Marshal.SizeOf(typeof(ErfResource))); for (int i = 0; i < newResources.Length; i++) newResources[i].OffsetToResource += offsetToData; // Create the new file and write the data to it. NWNLogger.Log(0, "module.SaveAs creating output file"); string newName = fileName + ".New"; using (FileStream writer = new FileStream(newName, FileMode.Create, FileAccess.Write, FileShare.Write)) { NWNLogger.Log(0, "module.SaveAs writing header"); newHeader.Serialize(writer); NWNLogger.Log(0, "module.SaveAs writing strings"); ErfString.Serialize(writer, descriptions); NWNLogger.Log(0, "module.SaveAs writing keys"); ErfKey.Serlialize(writer, newKeys); NWNLogger.Log(0, "module.SaveAs writing resources"); ErfResource.Serlialize(writer, newResources); NWNLogger.Log(0, "module.SaveAs writing raw data"); writer.Write(buffer.GetBuffer(), 0, (int) buffer.Length); NWNLogger.Log(0, "module.SaveAs flushing and closing"); writer.Flush(); writer.Close(); } // Delete the old file and rename the new file to the proper name. NWNLogger.Log(0, "module.SaveAs copying over current file"); File.Copy(newName, fileName, true); NWNLogger.Log(0, "module.SaveAs deleting"); File.Delete(newName); // Update the ERF's field's with the new values. NWNLogger.Log(0, "module.SaveAs updating object definition"); header = newHeader; keys = newKeys; resources = newResources; // Clear our string collections. replacedFileHash.Clear(); addedFileHash.Clear(); removedFiles.Clear(); fileInfo = new FileInfo(fileName); }
/// <summary> /// This method loads a single file from the specified erf, returning /// a MemoryStream containing the file's contents. /// </summary> /// <param name="erf">The erf containing the file</param> /// <param name="file">The file to load</param> /// <returns>A MemoryStream containing the file's data</returns> public static MemoryStream GetFile(string erf, string file) { // Open the erf file. NWNLogger.Log(0, "Erf.GetFile({0}, {1}) entering", erf, file); using (FileStream reader = new FileStream(erf, FileMode.Open, FileAccess.Read, FileShare.Read)) { // Read the header from the ERF ErfHeader header = new ErfHeader(reader); NWNLogger.Log(0, "Erf.GetFile({0}, {1}) has {2} files", erf, file, header.EntryCount); // Read the key (file) list from the ERF. reader.Seek(header.OffsetToKeyList, SeekOrigin.Begin); ErfKey[] keys = ErfKey.Deserialize(reader, header.EntryCount, header.Version); NWNLogger.Log(0, "Erf.GetFile({0}, {1}) read {2} keys", erf, file, keys.Length); // Read the resource (file) list from the ERF. reader.Seek(header.OffsetToResourceList, SeekOrigin.Begin); ErfResource[] resources = ErfResource.Deserialize(reader, header.EntryCount); NWNLogger.Log(0, "Erf.GetFile({0}, {1}) read {2} resources", erf, file, resources.Length); // Loop through all of the resources in the erf looking for the file. for (int i = 0; i < keys.Length; i++) { // Check to see if this is the file we're looking for. NWNLogger.Log(1, "Erf.GetFile('{0}', '{1}'), keys[{2}].FileName '{3}'", erf, file, i, keys[i].FileName); //if (keys[i].FileName.ToLower() == file.ToLower()) if (0 == string.Compare(keys[i].FileName, file, true, CultureInfo.InvariantCulture)) { NWNLogger.Log(1, "Erf.GetFile('{0}', '{1}'), match!", erf, file); // We found our file, create a MemoryStream large enough to hold the file's // data and load the data into the stream. byte[] buffer = new Byte[resources[i].ResourceSize]; reader.Seek(resources[i].OffsetToResource, SeekOrigin.Begin); reader.Read(buffer, 0, resources[i].ResourceSize); NWNLogger.Log(1, "Erf.GetFile('{0}', '{1}'), creating MemoryStream from {2} bytes!", erf, file, buffer.Length); return new MemoryStream(buffer, false); } } return null; } }