/// <summary> /// Saves the changes of the encapsulated addon to its file stream. /// </summary> /// <exception cref="IOException">Happens if there is a problem with creating the addon into its stream.</exception> public void Save() { OpenAddon.Sort(); try { // It is needed to create a new, temporary file where we write the addon first // Without it, we would "undermount" the current file // And end up overwriting the addon from where ContentFile.Content gets the data we would write. using (FileStream newAddon = new FileStream(AddonStream.Name + "_create", FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None)) { Writer.Create(OpenAddon, newAddon); // Copy the contents to the real file newAddon.Seek(0, SeekOrigin.Begin); AddonStream.Seek(0, SeekOrigin.Begin); AddonStream.SetLength(0); newAddon.CopyTo(AddonStream); AddonStream.Flush(); } } catch (IOException) { throw; } // If there were no errors creating and copying the temporary file, // I assume it is safe to delete. File.Delete(AddonStream.Name + "_create"); _modified = false; // Reload the content database of the open addon if (AddonReader == null) { try { AddonReader = new Reader(AddonStream); } catch (IOException) { throw; } } else { AddonReader.Reparse(); } // Convert all files in the open addon to addon-backed content storages // So after save, the application knows the file is now in the addon. // This also updates the fileIDs in case of a file was reordered when Sort() happened. foreach (Reader.IndexEntry entry in AddonReader.Index) { OpenAddon.Files.Where(f => f.Path == entry.Path).First().SwitchToAddonInstance(AddonReader, entry); } }
/// <summary> /// Loads the specified addon from the local filesystem and encapsulates it within a realtime instance. /// </summary> /// <param name="filename">The path to the file on the local filesystem.</param> /// <returns>A RealtimeAddon instance.</returns> /// <exception cref="FileNotFoundException">Happens if the specified file does not exist.</exception> /// <exception cref="IOException">Thrown if there is a problem opening the specified file.</exception> /// <exception cref="ReaderException">Thrown if the addon reader and parser encounters an error.</exception> /// <exception cref="ArgumentException">Happens if a file with the same path is already added.</exception> /// <exception cref="WhitelistException">There is a file prohibited from storing by the global whitelist.</exception> /// <exception cref="IgnoredException">There is a file prohibited from storing by the addon's ignore list.</exception> public static RealtimeAddon Load(string filename) { if (!File.Exists(filename)) { throw new FileNotFoundException("The specified file " + filename + " does not exist."); } FileStream fs; try { fs = new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.None); } catch (IOException) { throw; } Reader r; try { r = new Reader(fs); } catch (IOException) { throw; } catch (ReaderException) { throw; } Addon addon; try { addon = new Addon(r); } catch (ArgumentException) { throw; } catch (WhitelistException) { throw; } catch (IgnoredException) { throw; } RealtimeAddon realtime = new RealtimeAddon(addon, fs); realtime.AddonReader = r; return realtime; }
/// <summary> /// Initializes a new content file using an already existing file from an addon as storage. /// </summary> /// <param name="reader">The reader of the addon.</param> /// <param name="index">The index of the file to use.</param> public ContentFile(Reader reader, Reader.IndexEntry index) { Path = index.Path; Storage = ContentStorageType.AddonInstance; AssociatedReader = reader; ReaderFileEntry = index.FileNumber; }
/// <summary> /// Switches the current ContentFile to represent a file saved into an addon. /// Used after saving addons so that previous externally-saved entries are dropped in time. /// </summary> /// <param name="reader">The reader of the addon.</param> /// <param name="index">The index of the file to use.</param> public void SwitchToAddonInstance(Reader reader, Reader.IndexEntry index) { if (Storage == ContentStorageType.Filesystem) { AssociatedReader = reader; ReaderFileEntry = index.FileNumber; DisposeExternal(); Storage = ContentStorageType.AddonInstance; } else if (Storage == ContentStorageType.AddonInstance) { // Update the entry itself. There is no need to touch files on disk. AssociatedReader = reader; ReaderFileEntry = index.FileNumber; } }
/// <summary> /// Sets up a new instance of Addon using the data provided by the specified addon reader. /// </summary> /// <param name="reader">The addon reader which handled reading the addon file.</param> /// <exception cref="ArgumentException">Happens if a file with the same path is already added.</exception> /// <exception cref="WhitelistException">The file is prohibited from storing by the global whitelist.</exception> /// <exception cref="IgnoredException">The file is prohibited from storing by the addon's ignore list.</exception> public Addon(Reader reader) : this() { Author = reader.Author; Title = reader.Name; Description = reader.Description; Type = reader.Type; Tags = reader.Tags; AddonVersion = reader.Version; FormatVersion = reader.FormatVersion; SteamID = reader.SteamID; Timestamp = reader.Timestamp; foreach (Reader.IndexEntry file in reader.Index) { try { CheckRestrictions(file.Path); ContentFile contentFile = new ContentFile(reader, file); Files.Add(contentFile); } catch (WhitelistException) { throw; } catch (IgnoredException) { throw; } catch (ArgumentException) { throw; } } }