using System; using System.Collections.Generic; using System.Linq; using System.Text; using ScrewTurn.Wiki.PluginFramework; using System.IO; namespace ScrewTurn.Wiki { /// /// Manages files, directories and attachments. /// public static class FilesAndAttachments { #region Files /// /// Finds the provider that has a file. /// /// The full name of the file. /// The provider that has the file, or null if the file could not be found. public static IFilesStorageProviderV30 FindFileProvider(string fullName) { if(fullName == null) throw new ArgumentNullException("fullName"); if(string.IsNullOrEmpty(fullName)) throw new ArgumentException("Full Name cannot be empty", "fullName"); fullName = NormalizeFullName(fullName); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { FileDetails details = provider.GetFileDetails(fullName); if(details != null) return provider; } return null; } /// /// Gets the details of a file. /// /// The full name of the file. /// The details of the file, or null if no file is found. public static FileDetails GetFileDetails(string fullName) { if(fullName == null) throw new ArgumentNullException("fullName"); if(string.IsNullOrEmpty(fullName)) throw new ArgumentException("Full Name cannot be empty", "fullName"); fullName = NormalizeFullName(fullName); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { FileDetails details = provider.GetFileDetails(fullName); if(details != null) return details; } return null; } /// /// Retrieves a File. /// /// The full name of the File. /// The output stream. /// A value indicating whether or not to count this retrieval in the statistics. /// true if the file is retrieved, false otherwise. public static bool RetrieveFile(string fullName, Stream output, bool countHit) { if(fullName == null) throw new ArgumentNullException("fullName"); if(fullName.Length == 0) throw new ArgumentException("Full Name cannot be empty", "fullName"); if(output == null) throw new ArgumentNullException("destinationStream"); if(!output.CanWrite) throw new ArgumentException("Cannot write into Destination Stream", "destinationStream"); fullName = NormalizeFullName(fullName); IFilesStorageProviderV30 provider = FindFileProvider(fullName); if(provider == null) return false; else return provider.RetrieveFile(fullName, output, countHit); } #endregion #region Directories /// /// Finds the provider that has a directory. /// /// The full path of the directory. /// The provider that has the directory, or null if no directory is found. public static IFilesStorageProviderV30 FindDirectoryProvider(string fullPath) { if(fullPath == null) throw new ArgumentNullException("fullPath"); if(fullPath.Length == 0) throw new ArgumentException("Full Path cannot be empty"); fullPath = NormalizeFullPath(fullPath); // In order to verify that the full path exists, it is necessary to navigate // from the root down to the specified directory level // Example: /my/very/nested/directory/structure/ // 1. Check that / contains /my/ // 2. Check that /my/ contains /my/very/ // 3. ... // allLevels contains this: // /my/very/nested/directory/structure/ // /my/very/nested/directory/ // /my/very/nested/ // /my/very/ // /my/ // / string oneLevelUp = fullPath; List allLevels = new List(10); allLevels.Add(fullPath.ToLowerInvariant()); while(oneLevelUp != "/") { oneLevelUp = UpOneLevel(oneLevelUp); allLevels.Add(oneLevelUp.ToLowerInvariant()); } foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { bool allLevelsFound = true; for(int i = allLevels.Count - 1; i >= 1; i--) { string[] dirs = provider.ListDirectories(allLevels[i]); string nextLevel = (from d in dirs where d.ToLowerInvariant() == allLevels[i - 1] select d).FirstOrDefault(); if(string.IsNullOrEmpty(nextLevel)) { allLevelsFound = false; break; } } if(allLevelsFound) return provider; } return null; } /// /// Lists the directories in a directory. /// /// The full path. /// The directories. /// If the specified directory is the root, then the list is performed on all providers. public static string[] ListDirectories(string fullPath) { fullPath = NormalizeFullPath(fullPath); if(fullPath == "/") { List directories = new List(50); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { directories.AddRange(provider.ListDirectories(fullPath)); } directories.Sort(); return directories.ToArray(); } else { IFilesStorageProviderV30 provider = FindDirectoryProvider(fullPath); return provider.ListDirectories(fullPath); } } /// /// Lists the files in a directory. /// /// The full path. /// The files. /// If the specified directory is the root, then the list is performed on all providers. public static string[] ListFiles(string fullPath) { fullPath = NormalizeFullPath(fullPath); if(fullPath == "/") { List files = new List(50); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { files.AddRange(provider.ListFiles(fullPath)); } files.Sort(); return files.ToArray(); } else { IFilesStorageProviderV30 provider = FindDirectoryProvider(fullPath); return provider.ListFiles(fullPath); } } #endregion #region Page Attachments /// /// Finds the provider that has a page attachment. /// /// The page. /// The name of the attachment. /// The provider that has the attachment, or null if the attachment could not be found. public static IFilesStorageProviderV30 FindPageAttachmentProvider(PageInfo page, string attachmentName) { if(page == null) throw new ArgumentNullException("page"); if(attachmentName == null) throw new ArgumentNullException("attachmentName"); if(attachmentName.Length == 0) throw new ArgumentException("Attachment Name cannot be empty", "attachmentName"); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { FileDetails details = provider.GetPageAttachmentDetails(page, attachmentName); if(details != null) return provider; } return null; } /// /// Gets the details of a page attachment. /// /// The page. /// The name of the attachment. /// The details of the attachment, or null if the attachment could not be found. public static FileDetails GetPageAttachmentDetails(PageInfo page, string attachmentName) { if(page == null) throw new ArgumentNullException("page"); if(attachmentName == null) throw new ArgumentNullException("attachmentName"); if(attachmentName.Length == 0) throw new ArgumentException("Attachment Name cannot be empty", "attachmentName"); foreach(IFilesStorageProviderV30 provider in Collectors.FilesProviderCollector.AllProviders) { FileDetails details = provider.GetPageAttachmentDetails(page, attachmentName); if(details != null) return details; } return null; } /// /// Retrieves a Page Attachment. /// /// The Page Info that owns the Attachment. /// The name of the Attachment, for example "myfile.jpg". /// The output stream. /// A value indicating whether or not to count this retrieval in the statistics. /// true if the Attachment is retrieved, false otherwise. public static bool RetrievePageAttachment(PageInfo page, string attachmentName, Stream output, bool countHit) { if(page == null) throw new ArgumentNullException("pageInfo"); if(attachmentName == null) throw new ArgumentNullException("name"); if(attachmentName.Length == 0) throw new ArgumentException("Name cannot be empty", "name"); if(output == null) throw new ArgumentNullException("destinationStream"); if(!output.CanWrite) throw new ArgumentException("Cannot write into Destination Stream", "destinationStream"); IFilesStorageProviderV30 provider = FindPageAttachmentProvider(page, attachmentName); if(provider == null) return false; else return provider.RetrievePageAttachment(page, attachmentName, output, countHit); } #endregion /// /// Normalizes a full name. /// /// The full name. /// The normalized full name. private static string NormalizeFullName(string fullName) { if(!fullName.StartsWith("/")) fullName = "/" + fullName; return fullName; } /// /// Normalizes a full path. /// /// The full path. /// The normalized full path. private static string NormalizeFullPath(string fullPath) { if(fullPath == null) return "/"; if(!fullPath.StartsWith("/")) fullPath = "/" + fullPath; if(!fullPath.EndsWith("/")) fullPath += "/"; return fullPath; } /// /// Goes up one level in a directory path. /// /// The full path, normalized, different from "/". /// The directory. private static string UpOneLevel(string fullPath) { if(fullPath == "/") throw new ArgumentException("Cannot navigate up from the root"); string temp = fullPath.Trim('/'); int lastIndex = temp.LastIndexOf("/"); return "/" + temp.Substring(0, lastIndex + 1); } } }