public Archive(string name, Stream stream, ArchiveSaveMode saveMode = ArchiveSaveMode.Explicit) { Name = name; Stream = stream; SaveMode = saveMode; if (saveMode == ArchiveSaveMode.Immediate) { lock (_syncRoot) ArchiveHelpers.WriteHeader(Header, new BinaryWriter(stream)); } }
public void Reload() { CloseAllFiles(); Files.Clear(); var reader = new BinaryReader(Stream); Stream.Seek(0); lock (_syncRoot) { Header = ArchiveHelpers.ReadHeader(reader); Files = ArchiveHelpers.ReadIndex(this, reader); } }
public void Flush() { lock (_syncRoot) { if (!IsDirty) { return; } switch (SaveMode) { case ArchiveSaveMode.Explicit: case ArchiveSaveMode.Flush: string tmpFile = Path.ChangeExtension(Name, ".ykc.tmp") ?? ""; var tmp = new FileStream(tmpFile, FileMode.Create); var w = new BinaryWriter(tmp); ArchiveHelpers.WriteHeader(Header, w); // write names foreach (var file in Files.Values) { file.NameOffset = tmp.Position; w.WriteNullTerminatedString(file.Name); } // write data foreach (var file in Files.Values) { if (file.IsDirty && SaveMode == ArchiveSaveMode.Explicit) { file.DataOffset = tmp.Position; w.Write(file.NewData); } else { long dataOffset = tmp.Position; Stream.CopyRangeTo(tmp, file.DataOffset, file.DataLength); file.DataOffset = dataOffset; } } // write index Header.IndexOffset = (uint)tmp.Position; ArchiveHelpers.WriteIndex(Files, w); Header.IndexLength = (uint)(tmp.Position - Header.IndexOffset); // update header tmp.Seek(0); ArchiveHelpers.WriteHeader(Header, w); // swap files tmp.Close(); Stream.Close(); File.Delete(Name ?? ""); File.Move(tmpFile, Name ?? ""); // reload IsDirty = false; Stream = new FileStream(Name ?? "", FileMode.Open); Reload(); break; case ArchiveSaveMode.Immediate: Stream.Seek(0, SeekOrigin.End); w = new BinaryWriter(Stream); // write index Header.IndexOffset = (uint)Stream.Position; ArchiveHelpers.WriteIndex(Files, w); Header.IndexLength = (uint)(Stream.Position - Header.IndexOffset); // update header Stream.Seek(0); ArchiveHelpers.WriteHeader(Header, w); Stream.Flush(); break; default: return; } } }
internal bool SaveFile(ArchiveFile file, MemoryStream data) { lock (_syncRoot) { var w = new BinaryWriter(Stream); switch (SaveMode) { case ArchiveSaveMode.Explicit: // mark file as dirty, but don't save to disk MarkDirty(); file.MarkDirty(); file.NewData = data.ToArray(); file.DataLength = file.NewData.Length; return(true); case ArchiveSaveMode.Flush: MarkDirty(); // if index and the old file data are in the back of the file (this file was last updated), overwrite them. // otherwise, the old file data will be kept until Flush() is called and the entire archive is written again. long newFileOffset = Stream.Length; if (Header.IndexOffset + Header.IndexLength == newFileOffset) { // Index is at the end of the file, overwrite it newFileOffset = Header.IndexOffset; } if (file.DataOffset + file.DataLength == newFileOffset) { // Old file data is at the end, overwrite it newFileOffset = file.DataOffset; } file.DataOffset = newFileOffset; file.DataLength = data.Length; // write file data Stream.SetLength(newFileOffset); Stream.Seek(newFileOffset); data.Seek(0).CopyTo(Stream); // write index Header.IndexOffset = (uint)Stream.Position; ArchiveHelpers.WriteIndex(Files, w); // update header Stream.Seek(0); ArchiveHelpers.WriteHeader(Header, w); Stream.Flush(); return(true); case ArchiveSaveMode.Immediate: MarkDirty(); Stream.Seek(0, SeekOrigin.End); // write file name file.NameOffset = (uint)Stream.Position; w.WriteNullTerminatedString(file.Name); // write file data file.DataOffset = (uint)Stream.Position; data.Seek(0).CopyTo(Stream); file.DataLength = (uint)(Stream.Position - file.DataOffset); return(true); default: return(false); } } }