/// <summary> /// Attempt to load the session header from the specified entry, returning null if it can't be loaded /// </summary> /// <param name="zipEntry">The current entry</param> /// <returns>The session header, or null if it can't be loaded</returns> private static SessionHeader LoadSessionHeader(ZipArchiveEntry zipEntry) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Verbose, LogCategory, "Opening session file from zip file to read header", "Opening zip entry '{0}'.", zipEntry.Name); } SessionHeader header = null; try { using (var sourceFile = zipEntry.Open()) { //we need a SEEKABLE stream, so we need to make a memory stream to be seek-able. //read the file header first to find out how large the session header is (which can be any size) var fileHeaderBuffer = new byte[FileHeader.HeaderSize]; sourceFile.Read(fileHeaderBuffer, 0, fileHeaderBuffer.Length); FileHeader fileHeader = null; using (var memoryStream = new MemoryStream(fileHeaderBuffer)) { if (GLFReader.IsGLF(memoryStream, out fileHeader) == false) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Verbose, LogCategory, "Session file does not check out as a GLF file, skipping", "Zip entry: '{0}'.", zipEntry.Name); } return(header); } } var sessionHeaderBuffer = new byte[fileHeader.DataOffset]; //we have to copy the file header into it because we can't re-read those bytes (non-seek-able stream) fileHeaderBuffer.CopyTo(sessionHeaderBuffer, 0); sourceFile.Read(sessionHeaderBuffer, fileHeaderBuffer.Length, sessionHeaderBuffer.Length - fileHeaderBuffer.Length); using (var memoryStream = new MemoryStream(sessionHeaderBuffer)) { using (var sourceGlfFile = new GLFReader(memoryStream)) { if (sourceGlfFile.IsSessionStream) { header = sourceGlfFile.SessionHeader; } } } } } catch (Exception ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Warning, LogWriteMode.Queued, ex, LogCategory, "Unexpected exception while attempting to load a session header", "While opening the zip file entry '{0}' an exception was thrown reading the session header. Since this routine is designed to not generate exceptions this may indicate a flaw in the logic of the routine.\r\nException: {1}\r\n", zipEntry.Name, ex.Message); } } return(header); }
/// <summary> /// Adds the provided session to the package /// </summary> /// <param name="sessionStream"></param> public void AddSession(Stream sessionStream) { using (GLFReader glfReader = new GLFReader(sessionStream)) // This will dispose the stream when it is disposed. { if (!glfReader.IsSessionStream) { throw new GibraltarException("The data stream provided is not a valid session data stream."); } if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Verbose, LogCategory, "Stream is session file, attempting to load", null); } lock (m_Lock) { //Add this stream to our zip archive string fileName = glfReader.SessionHeader.HasFileInfo ? string.Format("{0}~{1}.{2}", glfReader.SessionHeader.Id, glfReader.SessionHeader.FileId, Log.LogExtension) : string.Format("{0}.{1}", glfReader.SessionHeader.Id, Log.LogExtension); string zipFilePath = GenerateFragmentPath(glfReader.SessionHeader.FileId); ZipArchiveEntry fragmentEntry; if (m_Archive.Mode == ZipArchiveMode.Update) { fragmentEntry = m_Archive.GetEntry(zipFilePath); if (fragmentEntry != null) { fragmentEntry.Delete(); //wipe out any existing entry } } fragmentEntry = m_Archive.CreateEntry(FragmentsFolder + "\\" + fileName, CompressionLevel.NoCompression); //session files are already highly compressed, no reason to waste effort. using (var zipStream = fragmentEntry.Open()) { FileSystemTools.StreamContentCopy(sessionStream, zipStream, false); // Copy the stream into our package's temp directory. } IsDirty = true; } } }
/// <summary> /// Load the specified session /// </summary> /// <returns>The loaded session. If no session can be found with the specified Id an ArgumentOutOfRangeException will be thrown.</returns> public Session GetSession(Guid sessionId, Guid?fileId = null) { Session requestedSession = null; lock (m_Lock) { SessionFileInfo <ZipArchiveEntry> sessionFileInfo; if (m_Sessions.TryGetValue(sessionId, out sessionFileInfo) == false) { throw new ArgumentOutOfRangeException(nameof(sessionId), "There is no session in the package with the provided id"); } //now load up all of the session fragments. var loadingCollection = new SessionCollection(); foreach (var fragment in sessionFileInfo.Fragments) { //we need a seek-able stream - so we'll extract the fragment into a temp file and go with that. if (fileId != null) { //we need to check the file Id to see if it's what they requested using (var reader = new GLFReader(FileSystemTools.GetTempFileStreamCopy(fragment.Open()))) { if (reader.SessionHeader.FileId != fileId.Value) { continue; } } } requestedSession = loadingCollection.Add(FileSystemTools.GetTempFileStreamCopy(fragment.Open()), true); } } if (requestedSession == null) { throw new ArgumentOutOfRangeException(nameof(fileId), "There is no session file in the package with the provided file id"); } return(requestedSession); }
/// <summary> /// Retrieve the ids of the sessions files known locally for the specified session /// </summary> /// <param name="sessionId"></param> /// <returns></returns> public IList <Guid> GetSessionFileIds(Guid sessionId) { lock (m_Lock) { SessionFileInfo <ZipArchiveEntry> sessionFileInfo; if (m_Sessions.TryGetValue(sessionId, out sessionFileInfo) == false) { throw new ArgumentOutOfRangeException(nameof(sessionId), "There is no session in the package with the provided id"); } var fileIds = new List <Guid>(); foreach (var fragment in sessionFileInfo.Fragments) { //this is kinda crappy - we have to make a copy of the whole fragment to get a seekable stream to read the id. using (var reader = new GLFReader(FileSystemTools.GetTempFileStreamCopy(fragment.Open()))) { fileIds.Add(reader.SessionHeader.FileId); } } return(fileIds); } }