Click here to Skip to main content
15,881,687 members
Articles / Desktop Programming / Windows Forms

Listing and Working with Files in Archives

Rate me:
Please Sign up or sign in to vote.
2.86/5 (6 votes)
22 Jun 2007CPOL 32.2K   529   23  
This article describes how to use CAKE3, which is a wrapper component for many archiver DLLs,
/*
 * Created by SharpDevelop.
 * User: LYCJ
 * Date: 20/11/2006
 * Time: 23:03
 * 
 * To change this template use Tools | Options | Coding | Edit Standard Headers.
 */

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Text;

namespace Cake3
{		
	/// <summary>
	/// Represent a list of archive contents (ContentType).
	/// </summary>
	public class ContentList : IEnumerable
	{
		/// <summary>
		/// Occur when the archive list is changed.
		/// </summary>
		public EventHandler OnItemChanged;		
		internal ContentType[] contentList = new ContentType[1];
		internal List<string> dirList = new List<string>();
		List<ContentType> outputList = new List<ContentType>();
		int outputListRevision = -1;		
		
		int count = 0;
        int revision = 0;        
        string directory = "";
        string mask = "*";
        SearchParam param = null;
        bool subdir = true;
        bool reverse = false;
                
        /// <summary>
        /// Gets or sets the directory.
        /// Only file(s) that match the directory will be listed.
        /// </summary>
        public string Directory
        {
        	get { return directory; }
        	set { 
        		if (value == directory) return;
        		if (value == "")
        			directory = ""; else
        			directory = Utils.AppendSlash(Utils.AppendFrontSlash(value)); 
        		Reset(); }
        }
        
        public string Mask
        {
        	get { return mask; }
        	set {
        		if (value == mask) return;
        		if (value == "")
        			mask = "*"; else
        			mask = value;
        		Reset(); }        	
        }
        
        public SearchParam SearchParam
        {
        	get { return param; }
        	set { param = value;
        		Reset(); }
        }
        
        /// <summary>
        /// Gets or sets to show sub-directory or not.
        /// </summary>
        public bool Subdir
        {
        	get { return subdir; }
        	set { subdir = value; Reset();  }
        }
        /// <summary>
        /// Get or sets the archive contents sort order.
        /// </summary>
        public bool Reverse
        {
        	get { return reverse; }
        	set { reverse = value; Reset(); }
        }     
        
        /// <summary>
        /// 
        /// </summary>
        //TODO: Uncodumented
        public static List<string> GetExtensionList(ContentList list)
		{
			list.Directory = "";
			list.SearchParam = null;
			list.Mask = "*";			
			List<string> retVal = new List<string>();
			foreach (ContentType ct in list)
			{
				string ext = Utils.ExtractFileExt(ct.fileName);
				if (retVal.IndexOf(ext.ToLower()) == -1)
					retVal.Add(ext.ToLower());
			}
			retVal.Sort();
			return retVal;
		}        
        /// <summary>
        /// Gets a list of all directories.
        /// </summary>
        /// <returns>All directories</returns>
        public List<string> GetDirectoryList()
		{        	
        	dirList.Sort();
			return dirList;
		}
        /// <summary>
        /// Get a list of sub-directories in the current directory.
        /// </summary>
        /// <returns>A list of sub-directories in the current directory.</returns>
        public List<string> GetSubdirectoryList()
        {
        	return GetSubdirectoryList(directory);
        }        
        /// <summary>
        /// Get a list of sub-directories in the specified directory.
        /// </summary>
        /// <param name="directory">Directory to poll.</param>
        /// <returns>A list of sub-directories.</returns>
        public List<string> GetSubdirectoryList(string directory)
        {
        	List<string> retVal = new List<string>();
        	List<string> dirList = GetDirectoryList();        	
        	
			foreach (string s in dirList)
			{
				if (s.IndexOf(directory) == 0)
				{
					string subdir = Utils.ExtractFirstDir(s, directory.Length);
				
					if (retVal.IndexOf(subdir) == -1)
        				retVal.Add(subdir);																				
				}
			}
			
			return retVal;
        }
        
        //TODO: Uncodumented
        public void AddDirectory(string dir)
        {
        	if (dirList.IndexOf(dir) == -1)
        		dirList.Add(dir);
        }
        
        void checkOutputList()
        {
        	if (outputListRevision != revision)
        	{
        		outputListRevision = revision;
        		outputList.Clear();
        		
        		foreach (ContentType ct in this)
        		{
        			outputList.Add(ct);        			
        		}
        			
        	}
        }
               
        void Reset()
        {
        	revision++;        	
        	this.GetEnumerator().Reset();   
        	checkOutputList();
        	if (OnItemChanged != null)
        		OnItemChanged(this, new EventArgs());
        }
        
        //TODO: Undocumented
        public bool haveFileMatched(SearchParam param)
        {
        	for (int i = 0; i < count; i++)
        	{
        		ContentType ct = this[i, false];        		
        		if (param.MatchFile(ct))
        				return true;        			
        	}
        	return false;
        }
        
        /// <summary>
        /// Gets or sets an archive content in the collection.
        /// </summary>
        public ContentType this[int index]
        {
        	get
        	{
        		checkOutputList();
        		return outputList[index];
        	}
        }

        internal ContentType this[int index, bool dummy]
        {
            get
            {
                CheckIndex( index );
                return( contentList[index] );
            }
            set
            {
                CheckIndex( index );
                contentList[index] = value;
                revision++;
            }
        }
        
        /// <summary>
        /// Gets the number of archive content that matched the requirement. (Directory and Subdir)
        /// </summary>
        public int Count
		{
			get
			{
				return( outputList.Count );
			}
		}
        /// <summary>
        /// Gets the number of all archive content.
        /// </summary>
        public int TotalCount
        {
			get
			{
				return( count );
			}
        }
               
		internal int Revision
		{
			get
			{
				return( revision );
			}
		}
		
		/// <summary>
		/// Gets whether the specified file exist in the contentlist.
		/// </summary>
		/// <param name="filename">File to search.</param>
		/// <returns>Whether the file exists.</returns>
		public bool FileExists(string filename)
		{
			foreach (ContentType ct in contentList)
			{
				if (ct.fileName == filename)
					return true;
			}
			
			return false;
		}
		
		/// <summary>
		/// Add a file to the content list.  (Internal use only)		
		/// </summary>
		/// <param name="content">Archive Content</param>
		public void Add( ContentType content )
		{
			if( count >= contentList.Length )
			{
				contentList = (ContentType[]) Resize( contentList, contentList.Length * 2 );
			}
			contentList[count++] = content;
			
			string path = Utils.ExtractFilePath(content.fileName);			 	
     		if (dirList.IndexOf(path) == -1)
        		dirList.Add(path);			
		}		
		/// <summary>
		/// Clear the content list.	 (Internal use only)
		/// </summary>
		public void Clear()
		{
			count = 0;
			outputListRevision = -1;
			outputList.Clear();
			dirList.Clear();
		}

		internal static Array Resize( Array array, int newSize )
		{
			Type type = array.GetType().GetElementType();
			Array newArray = Array.CreateInstance( type, newSize );
			Array.Copy( array, 0, newArray, 0, Math.Min( array.Length, newSize ));
			return newArray;
		}


        internal void CheckIndex( int index )
        {
            if( index >= count )
                throw new ArgumentOutOfRangeException( 
                                 @"Index value out of range" );
        }
        
        #region IComparable Members   
        
        internal static IComparer SortByFilePathName
        {
            get
            {
                return( (IComparer) new ContentType.SortByFilePathNameClass());
            }
        }
		
		internal static IComparer SortByFileName
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileNameClass());
            }
        }
		
		internal static IComparer SortByFileExt
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileExtClass());
            }
        }
		
		internal static IComparer SortByFileSize
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileSizeClass());
            }
        }
		
		internal static IComparer SortByFilePackedSize
        {
            get
            {
                return( (IComparer) new ContentType.SortByFilePackedSizeClass());
            }
        }
		
		internal static IComparer SortByFileTime
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileTimeClass());
            }
        }
		
		internal static IComparer SortByFileRatio
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileRatioClass());
            }
        }
		
		internal static IComparer SortByFileCRC
        {
            get
            {
                return( (IComparer) new ContentType.SortByFileCRCClass());
            }
        }
		
		#endregion
		
		/// <summary>
		/// Sort the content list based on filename.
		/// </summary>
		public void Sort()
		{
			Array.Sort( contentList, 0, count );
			Reset();
		}

		/// <summary>
		/// Sort the content list.
		/// </summary>
		/// <param name="sortMetric">Sort method.</param>
		public void Sort( ContentType.SortMetric sortMetric )
		{
			switch( sortMetric )
            {
				case ContentType.SortMetric.FilePathName:				
					Array.Sort( contentList, 0, count, SortByFilePathName );
                    break;
                case ContentType.SortMetric.FileName:				
					Array.Sort( contentList, 0, count, SortByFileName );
                    break;
                case ContentType.SortMetric.FileExt:				
					Array.Sort( contentList, 0, count, SortByFileExt );
                    break;
                case ContentType.SortMetric.FileSize:				
					Array.Sort( contentList, 0, count, SortByFileSize );
                    break;
                case ContentType.SortMetric.FilePackedSize:				
					Array.Sort( contentList, 0, count, SortByFilePackedSize );
                    break;
                case ContentType.SortMetric.FileTime:				
					Array.Sort( contentList, 0, count, SortByFileTime );
                    break;
                case ContentType.SortMetric.FileRatio:				
					Array.Sort( contentList, 0, count, SortByFileRatio );
                    break;
                case ContentType.SortMetric.FileCRC:				
					Array.Sort( contentList, 0, count, SortByFileCRC );
                    break;
			}
			Reset();
		}
		
		#region IEnumerable Members
		/// <summary>
		/// Gets ContentListEnumerator.  (Internal use only)
		/// </summary>
		/// <returns>ContentListEnumerator</returns>
		public IEnumerator GetEnumerator()
		{
			return( new ContentListEnumerator( this ));
		}

		#endregion
		
		/// <summary>
		/// Initalize a new instance of ContentList.
		/// </summary>
		public ContentList()
		{
			
		}
	}
	
	internal class ContentListEnumerator : IEnumerator
    {
        ContentList contentList;
        int index;
        int revision;

        #region IEnumerator Members

        /// <summary>
        /// Reset the enumerator.
        /// </summary>
        public void Reset()
        {
        	if (!contentList.Reverse)
        	{
            	index = -1;            	
        	}
        	else
        	{
        		index = contentList.TotalCount;
        	}
        	
        	revision = contentList.Revision;
        }

        /// <summary>
        /// Gets the element in the collection at the current position of the enumerator.
        /// </summary>
        public object Current
        {
            get
            {
                if( revision != contentList.Revision )
                    throw new InvalidOperationException( 
                            @"Collection modified while enumerating." );
                return( contentList[index,false] );
            }
        }
        
        bool isSameDirectory(string filename)
        {
        	if (contentList.Directory == "")
        		return true;
        	
        	if (!(filename.StartsWith(contentList.Directory)))
        		return false;
        	
        	if ( !contentList.Subdir && (filename.LastIndexOf('\\') > contentList.Directory.Length))
        		return false;        	        	
        	
        	return true;
        }
        	
        bool isMatchMask(string filename)
        {
        	if (contentList.Mask == "*")
        		return true;
        	
        	return (Utils.MatchMask(filename, contentList.Mask, true));
        }
        
        bool isMatchSearchParam(ContentType ct)
        {
        	if (contentList.SearchParam == null)
        		return true;
        	
        	return contentList.SearchParam.MatchFile(ct);        	
        }
        
		/// <summary>
		/// Move to next content.
		/// </summary>
		/// <returns>Wheather the operation success.</returns>
		public bool MoveNext()
		{
			if (!contentList.Reverse)
			{			
				index += 1;
			
				while (( index < contentList.TotalCount ) && 
				       (!(isSameDirectory(contentList[index,false].fileName)) ||
				        !(isMatchMask(contentList[index,false].fileName)) ||
				        !(isMatchSearchParam(contentList[index,false])))
				      )
				{
					index += 1;
				}
											
				return ( index < contentList.TotalCount );
			}
			else
			{
				index -= 1;
			
				while (( index >= 0 ) && 
				       (!(isSameDirectory(contentList[index,false].fileName)) ||
				       !(isMatchMask(contentList[index,false].fileName)) ||
				       !(isMatchSearchParam(contentList[index,false])))
				      )
				{
					index -= 1;
				}
				
				return (index >= 0);
			}
			
		}
	
		#endregion
		
		internal ContentListEnumerator( ContentList contentList )
		{
			this.contentList = contentList;
			Reset();
		}

	}


	public class SearchParamArg
	{
		public enum Operators
		{
			equal, 
			notequal,
			greater,
			smaller
		}
		public enum Keys
		{
			name,			//n
			path,			//p			
			size,			//s
			compsize,		//c
			date			//d
		}
		Keys argKey = Keys.name;
		string argValue = null;
		Operators argOp = Operators.equal;
		
		public Keys Key { get { return argKey; } }
		public string Value { get { return argValue; } }
		public Operators Operator { get { return argOp; } }
		
		public SearchParamArg(string searchString)
		{
			#region constructor						
			string op = "==";
			Int32 opPos = searchString.IndexOf(op);
			if (opPos == -1)
			{
				op = "!=";
				opPos = searchString.IndexOf(op);
				if (opPos == -1)
				{
					op = ">";
					opPos = searchString.IndexOf(op);
					
					if (opPos == -1)
					{
						op = "<";
						opPos = searchString.IndexOf(op);
												
						if (opPos == -1)
						{
							op = "=";
							opPos = searchString.IndexOf(op);
							
							if (opPos == -1)
							{
								argKey = Keys.name;
								argOp = Operators.equal;
								argValue = "*"+searchString+"*";
								return;
							}
						}
					}
				}
			}
						
			string key = searchString.Substring(0, opPos).Trim();
			string value = searchString.Substring(opPos+op.Length).Trim();
			
			switch (key.ToLower())
			{
				case "n" : argKey = Keys.name; break;
				case "p" : argKey = Keys.path; break;				
				case "s" : argKey = Keys.size; break;
				case "c" : argKey = Keys.compsize; break;
				case "d" : argKey = Keys.date; break;
								
				case "name": argKey = Keys.name; break;
				case "path" : argKey = Keys.path; break;
				case "size" : argKey = Keys.size; break;
				case "compsize" : argKey = Keys.compsize; break;
				case "date" : argKey = Keys.date; break;
			}
			
			
			switch (op)
			{
				case "!=" : argOp = Operators.notequal; break;
				case "==" : argOp = Operators.equal; break;
				case "=" : argOp = Operators.equal; break;
				case ">"  : argOp = Operators.greater; break;
				case "<"  : argOp = Operators.smaller; break;
			}
			
			argValue = value;
			#endregion
		}
		
		
		public bool MatchFile(ContentType ct)
		{
			switch (argKey)
			{
					case Keys.name : return MatchName(ct); 	
					case Keys.path : return MatchPath(ct); 	
					case Keys.date : return MatchDate(ct);
					case Keys.size : return MatchSize(ct);
					case Keys.compsize : return MatchSize(ct);
			}
			
			return false;
		}		
		#region MatchFileTools		
		bool MatchSize(ContentType ct)
		{
			uint size;
			try
			{
				size = Convert.ToUInt32(argValue);
			}				
			catch 
			{
				return false;
			}
							
				
			switch (argOp)
			{					
					case Operators.equal : return ct.fileSize == size;
					case Operators.notequal : return ct.fileSize != size;
					case Operators.greater : return ct.fileSize > size;
					case Operators.smaller : return ct.fileSize <= size;
			}
			return false;
		}				
		bool MatchCompSize(ContentType ct)
		{
			uint size;
			try
			{
				size = Convert.ToUInt32(argValue);
			}				
			catch 
			{
				return false;
			}
							
				
			switch (argOp)
			{					
					case Operators.equal : return ct.filePackedSize == size;
					case Operators.notequal : return ct.filePackedSize != size;
					case Operators.greater : return ct.filePackedSize > size;
					case Operators.smaller : return ct.filePackedSize <= size;
			}
			return false;
		}			
		bool MatchDate(ContentType ct)
		{
			DateTime date;
			try
			{
				//06-18-07 SearchParam.MatchDate parse datetime string correctly in all computers.
				IFormatProvider culture = new CultureInfo("en-US", true);
				date = DateTime.Parse(argValue, culture);
			}				
			catch 
			{
				return false;
			}
							
				
			switch (argOp)
			{					
					case Operators.equal : return ct.fileTime == date;
					case Operators.notequal : return ct.fileTime != date;
					case Operators.greater : return ct.fileTime > date;
					case Operators.smaller : return ct.fileTime <= date;
			}
			return false;
		}	
		bool MatchName(ContentType ct)
		{
			
			string[] maskList = argValue.Split(new char[] { ',' } );
			string filename = Utils.ExtractFileName(ct.fileName);
			switch (argOp)
			{
					case Operators.equal : 
					{
						foreach (string mask in maskList)
						{
							if (Utils.MatchMask(filename, mask, true))
							    return true;
						}
						return false;
					}
															
					case Operators.notequal : 
					{
						foreach (string mask in maskList)
						{
							if (Utils.MatchMask(filename, mask, true))
							    return false;
						}
						return true;
					}
			}
			return false;
		}		
		bool MatchPath(ContentType ct)
		{
			switch (argOp)
			{
					case Operators.equal : return Utils.MatchMask(Utils.ExtractFilePath(ct.fileName), argValue, true);
					case Operators.notequal : return !Utils.MatchMask(Utils.ExtractFilePath(ct.fileName), argValue, true);
			}
			return false;
		}
		#endregion
	}
	
	public class SearchParam
	{
		List<SearchParamArg> argList = new List<SearchParamArg>();
		public string Param = "";
		public string Tag = "";
		
		public SearchParam(string[] paramList)
		{
			foreach (string param in paramList)
			{
				argList.Add(new SearchParamArg(param));			
				if (Param == "")
					Param = param;
				else Param += ";" + param;
			}
		}
		
		public SearchParam(string paramList)
		{
			Param = paramList;
			string[] paramListArray = paramList.Split(new char[] { ';' } );
			foreach (string param in paramListArray)
				argList.Add(new SearchParamArg(param));						
		}
		
		public SearchParam(string paramList, string name) 
		{
			Tag = name;
			Param = paramList;
			string[] paramListArray = paramList.Split(new char[] { ';' } );
			foreach (string param in paramListArray)
				argList.Add(new SearchParamArg(param));			
		}
		
		public bool MatchFile(ContentType ct)
		{
			foreach (SearchParamArg arg in argList)
			{
				if (!arg.MatchFile(ct))
					return false;
			}
			return true;
		}
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder
Hong Kong Hong Kong

Comments and Discussions