/// <summary> /// Handles validation and stream preparation of a given transfer in order to read /// a given block of data. The actual reading (either into a buffer, or a returned /// stream) is being delegated via the <paramref name="dataReaderFunc"/>. /// </summary> /// <typeparam name="T">The type of <see cref="IDataBlock"/> that is being returned.</typeparam> /// <param name="transfer">The processed transfer.</param> /// <param name="blockNumber">The block number to be read.</param> /// <param name="dataReaderFunc">A function that receives the designated stream offset, /// and returns the required <see cref="IDataBlock"/> that provides the block's data.</param> /// <returns>The <see cref="IDataBlock"/> that is being created by the <paramref name="dataReaderFunc"/>.</returns> private static T PrepareAndRunBlockReading <T>(ZipDownloadTransfer transfer, long blockNumber, Func <Stream, long, T> dataReaderFunc) where T : IDataBlock { DownloadToken token = transfer.Token; long position = blockNumber * token.DownloadBlockSize; //in case of an invalid position, throw error if (position > token.ResourceLength) { string msg = "Cannot deliver block {0} - invalid block number (beyond actual file size)."; msg = String.Format(msg, blockNumber); throw new DataBlockException(msg); } ZipNode node = transfer.FileItem.Node; //TODO cache stream or even use temp file - this needs heavy optimization //open and position stream var stream = node.FileEntry.OpenReader(); stream.Position = position; T dataBlock = dataReaderFunc(stream, position); return(dataBlock); }
public async Task GetFilters() { using (var temp = new TempFile()) { using (var stream = temp.OpenWrite()) { using (var zip = StreamHelper.CreateZipArchive(stream, ZipArchiveMode.Create)) { StreamHelper.CreateZipArchiveEntry(zip, "binary.txt", TestFilterData.TextWithMixedBinary); StreamHelper.CreateZipArchiveEntry(zip, "text.txt", TestFilterData.TextWithBlankLines); StreamHelper.CreateZipArchiveEntry(zip, "text2.txt", TestFilterData.TextMixedLineEndings); } } var context = new Mock <FilterContext>(); context.Setup(x => x.CancellationToken).Returns(CancellationToken.None); var visitor = new Mock <INodeVisitor>(); visitor.Setup(x => x.Context).Returns(context.Object); visitor.Setup(x => x.Visit(It.IsAny <FileNode>())).Returns(Task.FromResult(1)); var node = new ZipNode(temp.File); await node.Accept(visitor.Object); visitor.Verify(x => x.Visit(It.IsAny <FileNode>()), Times.Exactly(3)); } }
private static void SetCommonProperties(VirtualResourceInfo resourceInfo, ZipNode node) { resourceInfo.FullName = node.FullName; resourceInfo.ParentFolderPath = node.ParentNode == null ? null : node.ParentNode.FullName; var entry = node.FileEntry; if (entry != null) { resourceInfo.Description = entry.Info; resourceInfo.IsHidden = (entry.Attributes & FileAttributes.Hidden) == FileAttributes.Hidden; resourceInfo.IsReadOnly = (entry.Attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly; resourceInfo.CreationTime = entry.CreationTime == DateTime.MinValue ? (DateTimeOffset?)null : entry.CreationTime.ToLocalTime(); resourceInfo.LastWriteTime = entry.LastModified == DateTime.MinValue ? (DateTimeOffset?)null : entry.LastModified.ToLocalTime(); } }
/// <summary> /// Recursively copies /// </summary> /// <param name="sourceFolderNode">Represents the folder that needs to copied.</param> /// <param name="targetFolderPath">The path of the target folder that corresponds to the /// submitted <paramref name="sourceFolderNode"/>.</param> protected virtual void CopyFolderContents(ZipNode sourceFolderNode, string targetFolderPath) { //create the target folder NodeRepository.ZipFile.AddDirectoryByName(targetFolderPath); foreach (var childFile in sourceFolderNode.ChildFiles) { //copy file string path = CreateFilePath(targetFolderPath, childFile.GetLocalName()); //create a deferred stream that extracts the file during writing var ds = new DeferredStream(() => Configuration.TempStreamFactory.CreateTempStream()); NodeRepository.ZipFile.AddEntry(path, s => ds, (s, n) => ds.Dispose()); } foreach (ZipNode childFolder in sourceFolderNode.ChildDirectories) { //create new target folder path and recurse string childPath = CreateFolderPath(targetFolderPath, childFolder.GetLocalName()); CopyFolderContents(childFolder, childPath); } }
public ZipFolderItem(ZipNode folderEntry, VirtualFolderInfo virtualFolder) { Node = folderEntry; ResourceInfo = virtualFolder; }
/// <summary> /// Links the entries of the encapsulated <see cref="ZipFile"/> and refreshes the /// <see cref="RootNodes"/> collection. /// </summary> public void Refresh() { RootNode = new ZipNode(RootFolderPath, true) { IsRootNode = true }; var entries = ZipFile.Entries.Select(e => new ZipNode(e)).ToArray(); for (int index = 0; index < entries.Length; index++) { var node = entries[index]; string parentPath = node.FullName.GetParentPath(); if (!IsRootPath(parentPath)) { //TODO currently, we require the node to have a parent entry if there's path //information that indicates so. According to ZIP specs, this might not necessarily //be the case... node.ParentNode = entries.Single(e => e.FullName == parentPath && e.IsDirectoryNode); node.ParentNode.RegisterChildNode(node); } } //get top level entries var topLevelEntries = entries.Where(e => e.ParentNode == null).ToArray(); //assign root entries to root node foreach (var entry in topLevelEntries) { RootNode.RegisterChildNode(entry); entry.ParentNode = RootNode; } }
/// <summary> /// Gets a file item for a known file entry within the /// maintained ZIP file. /// </summary> /// <param name="qualifiedName">The qualified name of the ZIP /// entry.</param> /// <returns>A file item that can be resolved to the requested ZIP /// entry.</returns> /// <exception cref="VirtualResourceNotFoundException">If the submitted /// path cannot be resolved to a maintained file entry.</exception> public ZipFileItem GetFileItem(string qualifiedName) { qualifiedName = qualifiedName.RemoveRootSlash(); var node = TryFindNode(qualifiedName); //if there is no such node, create a virtual one if (node == null) { node = new ZipNode(qualifiedName, false); node.ParentNode = TryFindNode(qualifiedName.GetParentPath()) ?? RootNode; } else if (node.IsDirectoryNode) { //throw exception if the path is already linked to a directory entry string msg = "Submitted file path [{0}] refers to a directory, not a file."; msg = String.Format(msg, qualifiedName); throw new ResourceAccessException(msg); } return new ZipFileItem(node, node.ToFileInfo()); }
public ZipFileItem(ZipNode node, VirtualFileInfo virtualFile) { Node = node; ResourceInfo = virtualFile; }