Пример #1
0
        private void RemoveItem(ArchivedFolder.Builder folder)
        {
            foreach (var item in mItemMap[folder])
            {
                RemoveItem(item);
            }

            mItemMap.Remove(folder);
        }
Пример #2
0
        private ArchivedFile.Builder AddItem(List <ArchivedItem.Builder> items, string fullName, int offset, bool isFile)
        {
            int ending = fullName.IndexOfAny(kFolderSeparators, offset);

            string itemName;

            if (ending < 0)
            {
                itemName = fullName.Substring(offset);
                if (isFile)
                {
                    return(AddFile(items, fullName, itemName));
                }
            }
            else
            {
                itemName = fullName.Substring(offset, ending - offset);
            }

            ArchivedFolder.Builder folder = null;
            foreach (var item in items)
            {
                if (String.Equals(item.Name, itemName, StringComparison.OrdinalIgnoreCase))
                {
                    folder = item as ArchivedFolder.Builder;
                    break;
                }
            }

            if (folder == null)
            {
                RemoveItem(items, itemName);
                folder          = new ArchivedFolder.Builder();
                folder.FullName = ending < 0 ? fullName : fullName.Substring(0, ending);
                folder.Name     = itemName;
                items.Add(folder);
                mItemMap.Add(folder, new List <ArchivedItem.Builder>());
            }

            if (ending < 0)
            {
                System.Diagnostics.Debug.Assert(!isFile);
                return(null);
            }

            return(AddItem(mItemMap[folder], fullName, ending + 1, isFile));
        }
Пример #3
0
        private ArchivedFolder BuildFolder(ArchivedFolder.Builder builder)
        {
            System.Diagnostics.Debug.Assert(builder.Items.Count == 0);

            foreach (var item in mItemMap[builder])
            {
                if (item is ArchivedFolder.Builder)
                {
                    builder.Items.Add(BuildFolder((ArchivedFolder.Builder)item));
                }
                else
                {
                    builder.Items.Add(((ArchivedFile.Builder)item).ToImmutable());
                }
            }

            return(builder.ToImmutable());
        }
Пример #4
0
        public ArchiveFileModel ReadMetadata(Stream stream, PasswordStorage password)
        {
            if (mIsRunning)
            {
                throw new InvalidOperationException("Recursive invocation.");
            }

            try
            {
                mIsRunning = true;

                // reset fields to detect bugs
                mFileNames = null;
                mItemsWithoutStreamMarkers = null;
                mEmptyFileMarkers          = null;
                mDeletionMarkers           = null;
                mOffsets            = null;
                mAttributes         = null;
                mCDates             = null;
                mMDates             = null;
                mADates             = null;
                mItemCount          = -1;
                mItemsWithoutStream = -1;

                var metadata = ReadMetadataCore(stream, password);

                mRootFolder = new ArchivedFolder.Builder();
                mItemMap    = new Dictionary <ArchivedFolder.Builder, List <ArchivedItem.Builder> >();
                mItemMap.Add(mRootFolder, new List <ArchivedItem.Builder>());
                mFiles      = new HashSet <ArchivedFile.Builder>();
                mStreamMap  = new List <ArchivedFile.Builder>();
                mSectionMap = ImmutableArray.CreateBuilder <int>(metadata.DecoderSections.Length + 1);

                ArchiveDecoderSection currentDecoder = null;
                int currentSectionIndex = -1;
                int currentStreamIndex  = 0;
                int currentStreamCount  = 0;
                int currentEmptyIndex   = 0;

                for (int currentFileIndex = 0; currentFileIndex < mFileNames.Count; currentFileIndex++)
                {
                    var  filename             = mFileNames[currentFileIndex];
                    bool hasStream            = false;
                    ArchivedFile.Builder file = null;

                    if (mItemsWithoutStreamMarkers != null && mItemsWithoutStreamMarkers[currentFileIndex])
                    {
                        var isFile           = (mEmptyFileMarkers == null || mEmptyFileMarkers[currentEmptyIndex]);
                        var isDeletionMarker = (mDeletionMarkers != null && mDeletionMarkers[currentEmptyIndex]);

                        if (isDeletionMarker)
                        {
                            RemoveItem(mItemMap[mRootFolder], filename, 0);
                        }
                        else
                        {
                            file = AddItem(mItemMap[mRootFolder], filename, 0, isFile);
                        }

                        currentEmptyIndex++;
                    }
                    else
                    {
                        hasStream = true;
                        file      = AddItem(mItemMap[mRootFolder], filename, 0, true);
                    }

                    if (file != null)
                    {
                        if (mOffsets != null)
                        {
                            file.Offset = mOffsets[currentFileIndex] ?? 0;
                        }

                        if (mAttributes != null)
                        {
                            var attr = mAttributes[currentFileIndex];

                            if (attr.HasValue && (attr.Value & ArchivedAttributesExtensions.DirectoryAttribute) != 0)
                            {
                                continue;
                            }

                            file.Attributes = attr;
                        }

                        if (mCDates != null)
                        {
                            file.Creation = mCDates[currentFileIndex];
                        }

                        if (mMDates != null)
                        {
                            file.LastWrite = mMDates[currentFileIndex];
                        }

                        if (mADates != null)
                        {
                            file.LastAccess = mADates[currentFileIndex];
                        }

                        if (hasStream)
                        {
                            while (currentStreamIndex == currentStreamCount)
                            {
                                if (currentSectionIndex == metadata.DecoderSections.Length - 1)
                                {
                                    throw new InvalidDataException();
                                }

                                currentDecoder     = metadata.DecoderSections[++currentSectionIndex];
                                currentStreamCount = currentDecoder.Streams.Length;
                                currentStreamIndex = 0;

                                mSectionMap.Add(mStreamMap.Count);
                            }

                            file.Stream = new DecodedStreamIndex(currentSectionIndex, currentStreamIndex);

                            var streamMetadata = currentDecoder.Streams[currentStreamIndex++];
                            file.Length   = streamMetadata.Length;
                            file.Checksum = streamMetadata.Checksum;
                        }
                    }

                    if (hasStream)
                    {
                        mStreamMap.Add(file);
                    }
                }

                var finalStreamMap = ImmutableList.CreateBuilder <ArchivedFile>();
                foreach (var file in mStreamMap)
                {
                    finalStreamMap.Add(mFiles.Contains(file) ? file.ToImmutable() : null);
                }

                if (currentStreamIndex != currentStreamCount || currentSectionIndex != metadata.DecoderSections.Length - 1)
                {
                    throw new InvalidDataException();
                }

                mSectionMap.Add(finalStreamMap.Count);

                return(new ArchiveFileModel(metadata, BuildFolder(mRootFolder), mSectionMap.MoveToImmutable(), finalStreamMap.ToImmutable()));
            }
            finally
            {
                mIsRunning = false;
            }
        }