/*
* 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;
}
}
}