Example #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);
        }
Example #2
0
        /// <summary>
        /// Read the main header of the archive.
        /// </summary>
        /// <returns>
        /// The main header of the archive
        /// </returns>
        public JpaArchiveHeader ReadArchiveHeader()
        {
            JpaArchiveHeader archiveHeader = new JpaArchiveHeader();

            // Initialize parts counter
            archiveHeader.TotalParts = 1;

            // Open the first part
            Open(1);

            archiveHeader.Signature = ReadAsciiString(3);

            if (archiveHeader.Signature != "JPA")
            {
                throw new InvalidArchiveException(String.Format(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_FILE_TYPE_SIGNATURE"), "JPA"));
            }

            archiveHeader.HeaderLength     = ReadUShort();
            archiveHeader.MajorVersion     = ReadByte();
            archiveHeader.MinorVersion     = ReadByte();
            archiveHeader.FileCount        = ReadULong();
            archiveHeader.UncompressedSize = ReadULong();
            archiveHeader.CompressedSize   = ReadULong();

            if (archiveHeader.HeaderLength > 19)
            {
                // We need to loop while we have remaining header bytes
                ushort remainingBytes = (ushort)(archiveHeader.HeaderLength - 19);

                while (remainingBytes > 0)
                {
                    // Do we have an extra header? The next three bytes must be JP followed by 0x01 and the header type
                    byte[] headerSignature = ReadBytes(4);

                    if ((headerSignature[0] != 0x4a) || (headerSignature[1] != 0x50) || (headerSignature[2] != 0x01))
                    {
                        throw new InvalidArchiveException(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_JPA_EXTRA_HEADER"));
                    }

                    // The next two bytes tell us how long this header is, without the 4 byte signature and type but WITH the header length field
                    ushort extraHeaderLength = ReadUShort();

                    // Subtract the read bytes from the remaining bytes in the header.
                    remainingBytes -= (ushort)(4 + extraHeaderLength);

                    // Read the extra header
                    switch (headerSignature[3])
                    {
                    case 0x01:
                        // Spanned Archive Marker header
                        archiveHeader.TotalParts = ReadUShort();

                        break;

                    default:
                        // I have no idea what this is!
                        throw new InvalidArchiveException(Language.ResourceManager.GetString("ERR_FORMAT_INVALID_JPA_EXTRA_HEADER"));
                    }
                }
            }

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

            // -- Get the total archive size by looping all of its parts
            info.ArchiveSize = 0;

            for (int i = 1; i <= Parts; i++)
            {
                FileInfo fi = new FileInfo(ArchivePath);
                info.ArchiveSize += (ulong)fi.Length;
            }

            archiveHeader.TotalLength = info.ArchiveSize;

            // -- Incorporate bits from the file header
            info.FileCount        = archiveHeader.FileCount;
            info.UncompressedSize = archiveHeader.UncompressedSize;
            info.CompressedSize   = archiveHeader.CompressedSize;
            // -- Create the event arguments object
            ArchiveInformationEventArgs args = new ArchiveInformationEventArgs(info);

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

            // Lastly, return the read archive header
            return(archiveHeader);
        }