public void ReadToFolder(PackageDataStream readStream, string rootDirectory) { if (readStream == null) { throw new ArgumentNullException(nameof(readStream)); } if (rootDirectory == null) { throw new ArgumentNullException(nameof(rootDirectory)); } rootDirectory = RemoveTrailingSlashIfPresent(rootDirectory); // ensure directory exists var rootDirectoryInfo = new DirectoryInfo(rootDirectory); rootDirectoryInfo.Create(); var version = serializer.Deserialize <ClientVersion>(readStream); compatibilityChecker.ThrowIfNotCompatibleWith("Package", version); var foldersStack = new Stack <string>(); while (true) { // read entry var entry = serializer.Deserialize <PackageEntry>(readStream); if (entry == null) { throw new InvalidOperationException("Cannot deserialize package entry."); } // final entry if (entry.Name == null) { // really end of stream? if (readStream.Position != readStream.Length) { throw new InvalidOperationException("Unexpected stream end."); } // final entry should pop to root directory if (entry.PopDirectories != foldersStack.Count) { throw new InvalidOperationException("Invalid number of directory pops on final entry."); } return; } EntriesCount++; // get to correct directory for (int i = 0; i < entry.PopDirectories; i++) { if (foldersStack.Count == 0) { throw new InvalidOperationException("Invalid number of directory pops."); } foldersStack.Pop(); } var currentFolder = foldersStack.Count > 0 ? foldersStack.Peek() : rootDirectory; var path = Path.Combine(currentFolder, entry.Name); // is it directory? if (entry.Attributes.HasFlag(FileAttributes.Directory)) { if (entry.FileSize != null) { throw new InvalidOperationException("File size is expected to be null for directory entry."); } var dir = new DirectoryInfo(path); if (dir.Exists) { throw new InvalidOperationException($"Folder \"{dir.Name}\" already exists. Full path: {dir.FullName}"); } dir.Create(); ApplyAttributes(dir, entry); foldersStack.Push(dir.FullName); continue; } // or is it file? if (entry.FileSize == null) { throw new InvalidOperationException("File size is null."); } using (var fileStream = new FileStream(path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None, DefaultBufferSize)) { fileStream.SetLength(entry.FileSize.Value); if (entry.FileSize.Value > 0) { // write content readStream.CopyStream(fileStream, DefaultBufferSize, entry.FileSize.Value); } } var fileInfo = new FileInfo(path); ApplyAttributes(fileInfo, entry); } }