Beispiel #1
0
        /// <summary>
        /// Implements the Extract method which extracts a backup archive. A DataWriter must be already assigned and configured or an
        /// exception will be raised.
        /// </summary>
        public override void Extract(CancellationToken token)
        {
            // Initialize
            Close();
            Progress.FilePosition        = 0;
            Progress.RunningCompressed   = 0;
            Progress.RunningUncompressed = 0;
            Progress.Status        = ExtractionStatus.Running;
            Progress.LastException = null;
            ProgressEventArgs args;

            try
            {
                // Read the file header
                JpaArchiveHeader archiveHeader = ReadArchiveHeader();

                // Invoke event at start of extraction
                args = new ProgressEventArgs(Progress);
                OnProgressEvent(args);

                while ((CurrentPartNumber != null) && (Progress.FilePosition < archiveHeader.TotalLength))
                {
                    JpaFileHeader fileHeader = ReadFileHeader();

                    // See https://www.codeproject.com/articles/742774/cancel-a-loop-in-a-task-with-cancellationtokens
                    if (token.IsCancellationRequested)
                    {
                        token.ThrowIfCancellationRequested();
                    }

                    ProcessDataBlock(fileHeader.CompressedSize, fileHeader.UncompressedSize, fileHeader.CompressionType, fileHeader.EntityType, fileHeader.EntityPath, token);

                    args = new ProgressEventArgs(Progress);
                    OnProgressEvent(args);
                }
            }
            catch (OperationCanceledException cancelledException)
            {
                // The operation was cancelled. Set the state to Idle and reset the extraction.
                Close();
                Progress.FilePosition        = 0;
                Progress.RunningCompressed   = 0;
                Progress.RunningUncompressed = 0;
                Progress.Status        = ExtractionStatus.Idle;
                Progress.LastException = cancelledException;

                // Invoke an event notifying susbcribers about the cancelation.
                args = new ProgressEventArgs(Progress);
                OnProgressEvent(args);

                return;
            }
            catch (Exception errorException)
            {
                // Any other exception. Close the option file and set the status to error.
                Close();
                Progress.Status        = ExtractionStatus.Error;
                Progress.LastException = errorException;

                // Invoke an event notifying of the error state
                args = new ProgressEventArgs(Progress);
                OnProgressEvent(args);

                return;
            }

            // Invoke an event signaling the end of extraction
            Progress.Status = ExtractionStatus.Finished;
            args            = new ProgressEventArgs(Progress);
            OnProgressEvent(args);
        }
Beispiel #2
0
        /// <summary>
        /// Reads the Entity Description Block in the current position of the JPA archive
        /// </summary>
        /// <returns>The entity description block (file header)</returns>
        public JpaFileHeader ReadFileHeader()
        {
            JpaFileHeader fileHeader = new JpaFileHeader();

            fileHeader.Signature = ReadAsciiString(3);

            if (fileHeader.Signature != "JPF")
            {
                throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_HEADER_AT_POSITION"), CurrentPartNumber, InputStream.Position - 3));
            }

            fileHeader.BlockLength        = ReadUShort();
            fileHeader.LengthOfEntityPath = ReadUShort();
            fileHeader.EntityPath         = ReadUtf8String(fileHeader.LengthOfEntityPath);
            fileHeader.EntityType         = (TEntityType)Enum.ToObject(typeof(TEntityType), ReadSByte());
            fileHeader.CompressionType    = (TCompressionType)Enum.ToObject(typeof(TCompressionType), ReadSByte());
            fileHeader.CompressedSize     = ReadULong();
            fileHeader.UncompressedSize   = ReadULong();
            fileHeader.EntityPermissions  = ReadULong();

            ushort standardEntityBlockLength = (ushort)(21 + fileHeader.LengthOfEntityPath);

            if (fileHeader.BlockLength > standardEntityBlockLength)
            {
                // We need to loop while we have remaining header bytes
                ushort remainingBytes = (ushort)(fileHeader.BlockLength - standardEntityBlockLength);

                while (remainingBytes > 0)
                {
                    // Get the extra header signature
                    byte[] headerSignature = ReadBytes(2);

                    // The next two bytes tell us how long this header is, including the signature
                    ushort extraHeaderLength = ReadUShort();

                    remainingBytes -= extraHeaderLength;

                    if ((headerSignature[0] == 0x00) && (headerSignature[1] == 0x01))
                    {
                        // Timestamp extra field
                        fileHeader.TimeStamp = ReadLong();
                    }
                    else
                    {
                        throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_EXTRA_HEADER_AT_POSITION"), CurrentPartNumber, InputStream.Position - 3));
                    }
                }
            }

            // Invoke the OnEntityEvent event. We need to do some work to get there, through...
            // -- Create a new archive information record
            EntityInformation info = new EntityInformation();

            // -- Incorporate bits from the file header
            info.CompressedSize   = fileHeader.CompressedSize;
            info.UncompressedSize = fileHeader.UncompressedSize;
            info.StoredName       = fileHeader.EntityPath;
            // -- Get the absolute path of the file
            info.AbsoluteName = "";

            if (DataWriter != null)
            {
                info.AbsoluteName = DataWriter.GetAbsoluteFilePath(fileHeader.EntityPath);
            }
            // -- Get some bits from the currently open archive file
            info.PartNumber = CurrentPartNumber ?? 1;
            info.PartOffset = InputStream.Position;
            // -- Create the event arguments object
            EntityEventArgs args = new EntityEventArgs(info);

            // -- Finally, invoke the event
            OnEntityEvent(args);

            // Lastly, return the read file header
            return(fileHeader);
        }